aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/Kconfig26
-rw-r--r--arch/arm/include/asm/perf_event.h17
-rw-r--r--arch/arm/include/asm/pmu.h27
-rw-r--r--arch/arm/kernel/perf_event.c928
-rw-r--r--arch/arm/kernel/pmu.c127
-rw-r--r--arch/arm/oprofile/Makefile7
-rw-r--r--arch/arm/oprofile/backtrace.c83
-rw-r--r--arch/arm/oprofile/common.c375
-rw-r--r--arch/arm/oprofile/op_arm_model.h35
-rw-r--r--arch/arm/oprofile/op_counter.h27
-rw-r--r--arch/arm/oprofile/op_model_arm11_core.c162
-rw-r--r--arch/arm/oprofile/op_model_arm11_core.h45
-rw-r--r--arch/arm/oprofile/op_model_mpcore.c306
-rw-r--r--arch/arm/oprofile/op_model_mpcore.h61
-rw-r--r--arch/arm/oprofile/op_model_v6.c78
-rw-r--r--arch/arm/oprofile/op_model_v7.c415
-rw-r--r--arch/arm/oprofile/op_model_v7.h103
-rw-r--r--arch/arm/oprofile/op_model_xscale.c444
18 files changed, 1316 insertions, 1950 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9e938a79a3b2..2b3157b5089a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -13,7 +13,7 @@ config ARM
13 select RTC_LIB 13 select RTC_LIB
14 select SYS_SUPPORTS_APM_EMULATION 14 select SYS_SUPPORTS_APM_EMULATION
15 select GENERIC_ATOMIC64 if (!CPU_32v6K) 15 select GENERIC_ATOMIC64 if (!CPU_32v6K)
16 select HAVE_OPROFILE 16 select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
17 select HAVE_ARCH_KGDB 17 select HAVE_ARCH_KGDB
18 select HAVE_KPROBES if (!XIP_KERNEL) 18 select HAVE_KPROBES if (!XIP_KERNEL)
19 select HAVE_KRETPROBES if (HAVE_KPROBES) 19 select HAVE_KRETPROBES if (HAVE_KPROBES)
@@ -181,28 +181,6 @@ config ARM_L1_CACHE_SHIFT_6
181 help 181 help
182 Setting ARM L1 cache line size to 64 Bytes. 182 Setting ARM L1 cache line size to 64 Bytes.
183 183
184if OPROFILE
185
186config OPROFILE_ARMV6
187 def_bool y
188 depends on CPU_V6 && !SMP
189 select OPROFILE_ARM11_CORE
190
191config OPROFILE_MPCORE
192 def_bool y
193 depends on CPU_V6 && SMP
194 select OPROFILE_ARM11_CORE
195
196config OPROFILE_ARM11_CORE
197 bool
198
199config OPROFILE_ARMV7
200 def_bool y
201 depends on CPU_V7 && !SMP
202 bool
203
204endif
205
206config VECTORS_BASE 184config VECTORS_BASE
207 hex 185 hex
208 default 0xffff0000 if MMU || CPU_HIGH_VECTOR 186 default 0xffff0000 if MMU || CPU_HIGH_VECTOR
@@ -1314,7 +1292,7 @@ config HIGHPTE
1314 1292
1315config HW_PERF_EVENTS 1293config HW_PERF_EVENTS
1316 bool "Enable hardware performance counter support for perf events" 1294 bool "Enable hardware performance counter support for perf events"
1317 depends on PERF_EVENTS && CPU_HAS_PMU && (CPU_V6 || CPU_V7) 1295 depends on PERF_EVENTS && CPU_HAS_PMU
1318 default y 1296 default y
1319 help 1297 help
1320 Enable hardware performance counter support for perf events. If 1298 Enable hardware performance counter support for perf events. If
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 49e3049aba32..48837e6d8887 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -28,4 +28,21 @@ set_perf_event_pending(void)
28 * same indexes here for consistency. */ 28 * same indexes here for consistency. */
29#define PERF_EVENT_INDEX_OFFSET 1 29#define PERF_EVENT_INDEX_OFFSET 1
30 30
31/* ARM perf PMU IDs for use by internal perf clients. */
32enum arm_perf_pmu_ids {
33 ARM_PERF_PMU_ID_XSCALE1 = 0,
34 ARM_PERF_PMU_ID_XSCALE2,
35 ARM_PERF_PMU_ID_V6,
36 ARM_PERF_PMU_ID_V6MP,
37 ARM_PERF_PMU_ID_CA8,
38 ARM_PERF_PMU_ID_CA9,
39 ARM_NUM_PMU_IDS,
40};
41
42extern enum arm_perf_pmu_ids
43armpmu_get_pmu_id(void);
44
45extern int
46armpmu_get_max_events(void);
47
31#endif /* __ARM_PERF_EVENT_H__ */ 48#endif /* __ARM_PERF_EVENT_H__ */
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 44bec1f02cb0..8ccea012722c 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -19,31 +19,26 @@ enum arm_pmu_type {
19 19
20#ifdef CONFIG_CPU_HAS_PMU 20#ifdef CONFIG_CPU_HAS_PMU
21 21
22struct pmu_irqs {
23 const int *irqs;
24 int num_irqs;
25};
26
27/** 22/**
28 * reserve_pmu() - reserve the hardware performance counters 23 * reserve_pmu() - reserve the hardware performance counters
29 * 24 *
30 * Reserve the hardware performance counters in the system for exclusive use. 25 * Reserve the hardware performance counters in the system for exclusive use.
31 * The 'struct pmu_irqs' for the system is returned on success, ERR_PTR() 26 * The platform_device for the system is returned on success, ERR_PTR()
32 * encoded error on failure. 27 * encoded error on failure.
33 */ 28 */
34extern const struct pmu_irqs * 29extern struct platform_device *
35reserve_pmu(void); 30reserve_pmu(enum arm_pmu_type device);
36 31
37/** 32/**
38 * release_pmu() - Relinquish control of the performance counters 33 * release_pmu() - Relinquish control of the performance counters
39 * 34 *
40 * Release the performance counters and allow someone else to use them. 35 * Release the performance counters and allow someone else to use them.
41 * Callers must have disabled the counters and released IRQs before calling 36 * Callers must have disabled the counters and released IRQs before calling
42 * this. The 'struct pmu_irqs' returned from reserve_pmu() must be passed as 37 * this. The platform_device returned from reserve_pmu() must be passed as
43 * a cookie. 38 * a cookie.
44 */ 39 */
45extern int 40extern int
46release_pmu(const struct pmu_irqs *irqs); 41release_pmu(struct platform_device *pdev);
47 42
48/** 43/**
49 * init_pmu() - Initialise the PMU. 44 * init_pmu() - Initialise the PMU.
@@ -53,24 +48,26 @@ release_pmu(const struct pmu_irqs *irqs);
53 * the actual hardware initialisation. 48 * the actual hardware initialisation.
54 */ 49 */
55extern int 50extern int
56init_pmu(void); 51init_pmu(enum arm_pmu_type device);
57 52
58#else /* CONFIG_CPU_HAS_PMU */ 53#else /* CONFIG_CPU_HAS_PMU */
59 54
60static inline const struct pmu_irqs * 55#include <linux/err.h>
61reserve_pmu(void) 56
57static inline struct platform_device *
58reserve_pmu(enum arm_pmu_type device)
62{ 59{
63 return ERR_PTR(-ENODEV); 60 return ERR_PTR(-ENODEV);
64} 61}
65 62
66static inline int 63static inline int
67release_pmu(const struct pmu_irqs *irqs) 64release_pmu(struct platform_device *pdev)
68{ 65{
69 return -ENODEV; 66 return -ENODEV;
70} 67}
71 68
72static inline int 69static inline int
73init_pmu(void) 70init_pmu(enum arm_pmu_type device)
74{ 71{
75 return -ENODEV; 72 return -ENODEV;
76} 73}
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 9e70f2053f9a..c45768614c8a 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -16,7 +16,9 @@
16 16
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/module.h>
19#include <linux/perf_event.h> 20#include <linux/perf_event.h>
21#include <linux/platform_device.h>
20#include <linux/spinlock.h> 22#include <linux/spinlock.h>
21#include <linux/uaccess.h> 23#include <linux/uaccess.h>
22 24
@@ -26,7 +28,7 @@
26#include <asm/pmu.h> 28#include <asm/pmu.h>
27#include <asm/stacktrace.h> 29#include <asm/stacktrace.h>
28 30
29static const struct pmu_irqs *pmu_irqs; 31static struct platform_device *pmu_device;
30 32
31/* 33/*
32 * Hardware lock to serialize accesses to PMU registers. Needed for the 34 * Hardware lock to serialize accesses to PMU registers. Needed for the
@@ -67,8 +69,18 @@ struct cpu_hw_events {
67}; 69};
68DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); 70DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
69 71
72/* PMU names. */
73static const char *arm_pmu_names[] = {
74 [ARM_PERF_PMU_ID_XSCALE1] = "xscale1",
75 [ARM_PERF_PMU_ID_XSCALE2] = "xscale2",
76 [ARM_PERF_PMU_ID_V6] = "v6",
77 [ARM_PERF_PMU_ID_V6MP] = "v6mpcore",
78 [ARM_PERF_PMU_ID_CA8] = "ARMv7 Cortex-A8",
79 [ARM_PERF_PMU_ID_CA9] = "ARMv7 Cortex-A9",
80};
81
70struct arm_pmu { 82struct arm_pmu {
71 char *name; 83 enum arm_perf_pmu_ids id;
72 irqreturn_t (*handle_irq)(int irq_num, void *dev); 84 irqreturn_t (*handle_irq)(int irq_num, void *dev);
73 void (*enable)(struct hw_perf_event *evt, int idx); 85 void (*enable)(struct hw_perf_event *evt, int idx);
74 void (*disable)(struct hw_perf_event *evt, int idx); 86 void (*disable)(struct hw_perf_event *evt, int idx);
@@ -87,6 +99,30 @@ struct arm_pmu {
87/* Set at runtime when we know what CPU type we are. */ 99/* Set at runtime when we know what CPU type we are. */
88static const struct arm_pmu *armpmu; 100static const struct arm_pmu *armpmu;
89 101
102enum arm_perf_pmu_ids
103armpmu_get_pmu_id(void)
104{
105 int id = -ENODEV;
106
107 if (armpmu != NULL)
108 id = armpmu->id;
109
110 return id;
111}
112EXPORT_SYMBOL_GPL(armpmu_get_pmu_id);
113
114int
115armpmu_get_max_events(void)
116{
117 int max_events = 0;
118
119 if (armpmu != NULL)
120 max_events = armpmu->num_events;
121
122 return max_events;
123}
124EXPORT_SYMBOL_GPL(armpmu_get_max_events);
125
90#define HW_OP_UNSUPPORTED 0xFFFF 126#define HW_OP_UNSUPPORTED 0xFFFF
91 127
92#define C(_x) \ 128#define C(_x) \
@@ -314,38 +350,44 @@ validate_group(struct perf_event *event)
314static int 350static int
315armpmu_reserve_hardware(void) 351armpmu_reserve_hardware(void)
316{ 352{
317 int i; 353 int i, err = -ENODEV, irq;
318 int err;
319 354
320 pmu_irqs = reserve_pmu(); 355 pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU);
321 if (IS_ERR(pmu_irqs)) { 356 if (IS_ERR(pmu_device)) {
322 pr_warning("unable to reserve pmu\n"); 357 pr_warning("unable to reserve pmu\n");
323 return PTR_ERR(pmu_irqs); 358 return PTR_ERR(pmu_device);
324 } 359 }
325 360
326 init_pmu(); 361 init_pmu(ARM_PMU_DEVICE_CPU);
327 362
328 if (pmu_irqs->num_irqs < 1) { 363 if (pmu_device->num_resources < 1) {
329 pr_err("no irqs for PMUs defined\n"); 364 pr_err("no irqs for PMUs defined\n");
330 return -ENODEV; 365 return -ENODEV;
331 } 366 }
332 367
333 for (i = 0; i < pmu_irqs->num_irqs; ++i) { 368 for (i = 0; i < pmu_device->num_resources; ++i) {
334 err = request_irq(pmu_irqs->irqs[i], armpmu->handle_irq, 369 irq = platform_get_irq(pmu_device, i);
370 if (irq < 0)
371 continue;
372
373 err = request_irq(irq, armpmu->handle_irq,
335 IRQF_DISABLED | IRQF_NOBALANCING, 374 IRQF_DISABLED | IRQF_NOBALANCING,
336 "armpmu", NULL); 375 "armpmu", NULL);
337 if (err) { 376 if (err) {
338 pr_warning("unable to request IRQ%d for ARM " 377 pr_warning("unable to request IRQ%d for ARM perf "
339 "perf counters\n", pmu_irqs->irqs[i]); 378 "counters\n", irq);
340 break; 379 break;
341 } 380 }
342 } 381 }
343 382
344 if (err) { 383 if (err) {
345 for (i = i - 1; i >= 0; --i) 384 for (i = i - 1; i >= 0; --i) {
346 free_irq(pmu_irqs->irqs[i], NULL); 385 irq = platform_get_irq(pmu_device, i);
347 release_pmu(pmu_irqs); 386 if (irq >= 0)
348 pmu_irqs = NULL; 387 free_irq(irq, NULL);
388 }
389 release_pmu(pmu_device);
390 pmu_device = NULL;
349 } 391 }
350 392
351 return err; 393 return err;
@@ -354,14 +396,17 @@ armpmu_reserve_hardware(void)
354static void 396static void
355armpmu_release_hardware(void) 397armpmu_release_hardware(void)
356{ 398{
357 int i; 399 int i, irq;
358 400
359 for (i = pmu_irqs->num_irqs - 1; i >= 0; --i) 401 for (i = pmu_device->num_resources - 1; i >= 0; --i) {
360 free_irq(pmu_irqs->irqs[i], NULL); 402 irq = platform_get_irq(pmu_device, i);
403 if (irq >= 0)
404 free_irq(irq, NULL);
405 }
361 armpmu->stop(); 406 armpmu->stop();
362 407
363 release_pmu(pmu_irqs); 408 release_pmu(pmu_device);
364 pmu_irqs = NULL; 409 pmu_device = NULL;
365} 410}
366 411
367static atomic_t active_events = ATOMIC_INIT(0); 412static atomic_t active_events = ATOMIC_INIT(0);
@@ -1144,7 +1189,7 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,
1144} 1189}
1145 1190
1146static const struct arm_pmu armv6pmu = { 1191static const struct arm_pmu armv6pmu = {
1147 .name = "v6", 1192 .id = ARM_PERF_PMU_ID_V6,
1148 .handle_irq = armv6pmu_handle_irq, 1193 .handle_irq = armv6pmu_handle_irq,
1149 .enable = armv6pmu_enable_event, 1194 .enable = armv6pmu_enable_event,
1150 .disable = armv6pmu_disable_event, 1195 .disable = armv6pmu_disable_event,
@@ -1167,7 +1212,7 @@ static const struct arm_pmu armv6pmu = {
1167 * reset the period and enable the interrupt reporting. 1212 * reset the period and enable the interrupt reporting.
1168 */ 1213 */
1169static const struct arm_pmu armv6mpcore_pmu = { 1214static const struct arm_pmu armv6mpcore_pmu = {
1170 .name = "v6mpcore", 1215 .id = ARM_PERF_PMU_ID_V6MP,
1171 .handle_irq = armv6pmu_handle_irq, 1216 .handle_irq = armv6pmu_handle_irq,
1172 .enable = armv6pmu_enable_event, 1217 .enable = armv6pmu_enable_event,
1173 .disable = armv6mpcore_pmu_disable_event, 1218 .disable = armv6mpcore_pmu_disable_event,
@@ -1197,10 +1242,6 @@ static const struct arm_pmu armv6mpcore_pmu = {
1197 * counter and all 4 performance counters together can be reset separately. 1242 * counter and all 4 performance counters together can be reset separately.
1198 */ 1243 */
1199 1244
1200#define ARMV7_PMU_CORTEX_A8_NAME "ARMv7 Cortex-A8"
1201
1202#define ARMV7_PMU_CORTEX_A9_NAME "ARMv7 Cortex-A9"
1203
1204/* Common ARMv7 event types */ 1245/* Common ARMv7 event types */
1205enum armv7_perf_types { 1246enum armv7_perf_types {
1206 ARMV7_PERFCTR_PMNC_SW_INCR = 0x00, 1247 ARMV7_PERFCTR_PMNC_SW_INCR = 0x00,
@@ -2079,6 +2120,803 @@ static u32 __init armv7_reset_read_pmnc(void)
2079 return nb_cnt + 1; 2120 return nb_cnt + 1;
2080} 2121}
2081 2122
2123/*
2124 * ARMv5 [xscale] Performance counter handling code.
2125 *
2126 * Based on xscale OProfile code.
2127 *
2128 * There are two variants of the xscale PMU that we support:
2129 * - xscale1pmu: 2 event counters and a cycle counter
2130 * - xscale2pmu: 4 event counters and a cycle counter
2131 * The two variants share event definitions, but have different
2132 * PMU structures.
2133 */
2134
2135enum xscale_perf_types {
2136 XSCALE_PERFCTR_ICACHE_MISS = 0x00,
2137 XSCALE_PERFCTR_ICACHE_NO_DELIVER = 0x01,
2138 XSCALE_PERFCTR_DATA_STALL = 0x02,
2139 XSCALE_PERFCTR_ITLB_MISS = 0x03,
2140 XSCALE_PERFCTR_DTLB_MISS = 0x04,
2141 XSCALE_PERFCTR_BRANCH = 0x05,
2142 XSCALE_PERFCTR_BRANCH_MISS = 0x06,
2143 XSCALE_PERFCTR_INSTRUCTION = 0x07,
2144 XSCALE_PERFCTR_DCACHE_FULL_STALL = 0x08,
2145 XSCALE_PERFCTR_DCACHE_FULL_STALL_CONTIG = 0x09,
2146 XSCALE_PERFCTR_DCACHE_ACCESS = 0x0A,
2147 XSCALE_PERFCTR_DCACHE_MISS = 0x0B,
2148 XSCALE_PERFCTR_DCACHE_WRITE_BACK = 0x0C,
2149 XSCALE_PERFCTR_PC_CHANGED = 0x0D,
2150 XSCALE_PERFCTR_BCU_REQUEST = 0x10,
2151 XSCALE_PERFCTR_BCU_FULL = 0x11,
2152 XSCALE_PERFCTR_BCU_DRAIN = 0x12,
2153 XSCALE_PERFCTR_BCU_ECC_NO_ELOG = 0x14,
2154 XSCALE_PERFCTR_BCU_1_BIT_ERR = 0x15,
2155 XSCALE_PERFCTR_RMW = 0x16,
2156 /* XSCALE_PERFCTR_CCNT is not hardware defined */
2157 XSCALE_PERFCTR_CCNT = 0xFE,
2158 XSCALE_PERFCTR_UNUSED = 0xFF,
2159};
2160
2161enum xscale_counters {
2162 XSCALE_CYCLE_COUNTER = 1,
2163 XSCALE_COUNTER0,
2164 XSCALE_COUNTER1,
2165 XSCALE_COUNTER2,
2166 XSCALE_COUNTER3,
2167};
2168
2169static const unsigned xscale_perf_map[PERF_COUNT_HW_MAX] = {
2170 [PERF_COUNT_HW_CPU_CYCLES] = XSCALE_PERFCTR_CCNT,
2171 [PERF_COUNT_HW_INSTRUCTIONS] = XSCALE_PERFCTR_INSTRUCTION,
2172 [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,
2173 [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,
2174 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = XSCALE_PERFCTR_BRANCH,
2175 [PERF_COUNT_HW_BRANCH_MISSES] = XSCALE_PERFCTR_BRANCH_MISS,
2176 [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED,
2177};
2178
2179static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
2180 [PERF_COUNT_HW_CACHE_OP_MAX]
2181 [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
2182 [C(L1D)] = {
2183 [C(OP_READ)] = {
2184 [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS,
2185 [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS,
2186 },
2187 [C(OP_WRITE)] = {
2188 [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS,
2189 [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS,
2190 },
2191 [C(OP_PREFETCH)] = {
2192 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2193 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2194 },
2195 },
2196 [C(L1I)] = {
2197 [C(OP_READ)] = {
2198 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2199 [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS,
2200 },
2201 [C(OP_WRITE)] = {
2202 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2203 [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS,
2204 },
2205 [C(OP_PREFETCH)] = {
2206 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2207 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2208 },
2209 },
2210 [C(LL)] = {
2211 [C(OP_READ)] = {
2212 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2213 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2214 },
2215 [C(OP_WRITE)] = {
2216 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2217 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2218 },
2219 [C(OP_PREFETCH)] = {
2220 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2221 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2222 },
2223 },
2224 [C(DTLB)] = {
2225 [C(OP_READ)] = {
2226 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2227 [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS,
2228 },
2229 [C(OP_WRITE)] = {
2230 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2231 [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS,
2232 },
2233 [C(OP_PREFETCH)] = {
2234 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2235 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2236 },
2237 },
2238 [C(ITLB)] = {
2239 [C(OP_READ)] = {
2240 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2241 [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS,
2242 },
2243 [C(OP_WRITE)] = {
2244 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2245 [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS,
2246 },
2247 [C(OP_PREFETCH)] = {
2248 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2249 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2250 },
2251 },
2252 [C(BPU)] = {
2253 [C(OP_READ)] = {
2254 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2255 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2256 },
2257 [C(OP_WRITE)] = {
2258 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2259 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2260 },
2261 [C(OP_PREFETCH)] = {
2262 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
2263 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
2264 },
2265 },
2266};
2267
2268#define XSCALE_PMU_ENABLE 0x001
2269#define XSCALE_PMN_RESET 0x002
2270#define XSCALE_CCNT_RESET 0x004
2271#define XSCALE_PMU_RESET (CCNT_RESET | PMN_RESET)
2272#define XSCALE_PMU_CNT64 0x008
2273
2274static inline int
2275xscalepmu_event_map(int config)
2276{
2277 int mapping = xscale_perf_map[config];
2278 if (HW_OP_UNSUPPORTED == mapping)
2279 mapping = -EOPNOTSUPP;
2280 return mapping;
2281}
2282
2283static u64
2284xscalepmu_raw_event(u64 config)
2285{
2286 return config & 0xff;
2287}
2288
2289#define XSCALE1_OVERFLOWED_MASK 0x700
2290#define XSCALE1_CCOUNT_OVERFLOW 0x400
2291#define XSCALE1_COUNT0_OVERFLOW 0x100
2292#define XSCALE1_COUNT1_OVERFLOW 0x200
2293#define XSCALE1_CCOUNT_INT_EN 0x040
2294#define XSCALE1_COUNT0_INT_EN 0x010
2295#define XSCALE1_COUNT1_INT_EN 0x020
2296#define XSCALE1_COUNT0_EVT_SHFT 12
2297#define XSCALE1_COUNT0_EVT_MASK (0xff << XSCALE1_COUNT0_EVT_SHFT)
2298#define XSCALE1_COUNT1_EVT_SHFT 20
2299#define XSCALE1_COUNT1_EVT_MASK (0xff << XSCALE1_COUNT1_EVT_SHFT)
2300
2301static inline u32
2302xscale1pmu_read_pmnc(void)
2303{
2304 u32 val;
2305 asm volatile("mrc p14, 0, %0, c0, c0, 0" : "=r" (val));
2306 return val;
2307}
2308
2309static inline void
2310xscale1pmu_write_pmnc(u32 val)
2311{
2312 /* upper 4bits and 7, 11 are write-as-0 */
2313 val &= 0xffff77f;
2314 asm volatile("mcr p14, 0, %0, c0, c0, 0" : : "r" (val));
2315}
2316
2317static inline int
2318xscale1_pmnc_counter_has_overflowed(unsigned long pmnc,
2319 enum xscale_counters counter)
2320{
2321 int ret = 0;
2322
2323 switch (counter) {
2324 case XSCALE_CYCLE_COUNTER:
2325 ret = pmnc & XSCALE1_CCOUNT_OVERFLOW;
2326 break;
2327 case XSCALE_COUNTER0:
2328 ret = pmnc & XSCALE1_COUNT0_OVERFLOW;
2329 break;
2330 case XSCALE_COUNTER1:
2331 ret = pmnc & XSCALE1_COUNT1_OVERFLOW;
2332 break;
2333 default:
2334 WARN_ONCE(1, "invalid counter number (%d)\n", counter);
2335 }
2336
2337 return ret;
2338}
2339
2340static irqreturn_t
2341xscale1pmu_handle_irq(int irq_num, void *dev)
2342{
2343 unsigned long pmnc;
2344 struct perf_sample_data data;
2345 struct cpu_hw_events *cpuc;
2346 struct pt_regs *regs;
2347 int idx;
2348
2349 /*
2350 * NOTE: there's an A stepping erratum that states if an overflow
2351 * bit already exists and another occurs, the previous
2352 * Overflow bit gets cleared. There's no workaround.
2353 * Fixed in B stepping or later.
2354 */
2355 pmnc = xscale1pmu_read_pmnc();
2356
2357 /*
2358 * Write the value back to clear the overflow flags. Overflow
2359 * flags remain in pmnc for use below. We also disable the PMU
2360 * while we process the interrupt.
2361 */
2362 xscale1pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);
2363
2364 if (!(pmnc & XSCALE1_OVERFLOWED_MASK))
2365 return IRQ_NONE;
2366
2367 regs = get_irq_regs();
2368
2369 perf_sample_data_init(&data, 0);
2370
2371 cpuc = &__get_cpu_var(cpu_hw_events);
2372 for (idx = 0; idx <= armpmu->num_events; ++idx) {
2373 struct perf_event *event = cpuc->events[idx];
2374 struct hw_perf_event *hwc;
2375
2376 if (!test_bit(idx, cpuc->active_mask))
2377 continue;
2378
2379 if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))
2380 continue;
2381
2382 hwc = &event->hw;
2383 armpmu_event_update(event, hwc, idx);
2384 data.period = event->hw.last_period;
2385 if (!armpmu_event_set_period(event, hwc, idx))
2386 continue;
2387
2388 if (perf_event_overflow(event, 0, &data, regs))
2389 armpmu->disable(hwc, idx);
2390 }
2391
2392 perf_event_do_pending();
2393
2394 /*
2395 * Re-enable the PMU.
2396 */
2397 pmnc = xscale1pmu_read_pmnc() | XSCALE_PMU_ENABLE;
2398 xscale1pmu_write_pmnc(pmnc);
2399
2400 return IRQ_HANDLED;
2401}
2402
2403static void
2404xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)
2405{
2406 unsigned long val, mask, evt, flags;
2407
2408 switch (idx) {
2409 case XSCALE_CYCLE_COUNTER:
2410 mask = 0;
2411 evt = XSCALE1_CCOUNT_INT_EN;
2412 break;
2413 case XSCALE_COUNTER0:
2414 mask = XSCALE1_COUNT0_EVT_MASK;
2415 evt = (hwc->config_base << XSCALE1_COUNT0_EVT_SHFT) |
2416 XSCALE1_COUNT0_INT_EN;
2417 break;
2418 case XSCALE_COUNTER1:
2419 mask = XSCALE1_COUNT1_EVT_MASK;
2420 evt = (hwc->config_base << XSCALE1_COUNT1_EVT_SHFT) |
2421 XSCALE1_COUNT1_INT_EN;
2422 break;
2423 default:
2424 WARN_ONCE(1, "invalid counter number (%d)\n", idx);
2425 return;
2426 }
2427
2428 spin_lock_irqsave(&pmu_lock, flags);
2429 val = xscale1pmu_read_pmnc();
2430 val &= ~mask;
2431 val |= evt;
2432 xscale1pmu_write_pmnc(val);
2433 spin_unlock_irqrestore(&pmu_lock, flags);
2434}
2435
2436static void
2437xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)
2438{
2439 unsigned long val, mask, evt, flags;
2440
2441 switch (idx) {
2442 case XSCALE_CYCLE_COUNTER:
2443 mask = XSCALE1_CCOUNT_INT_EN;
2444 evt = 0;
2445 break;
2446 case XSCALE_COUNTER0:
2447 mask = XSCALE1_COUNT0_INT_EN | XSCALE1_COUNT0_EVT_MASK;
2448 evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT0_EVT_SHFT;
2449 break;
2450 case XSCALE_COUNTER1:
2451 mask = XSCALE1_COUNT1_INT_EN | XSCALE1_COUNT1_EVT_MASK;
2452 evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT1_EVT_SHFT;
2453 break;
2454 default:
2455 WARN_ONCE(1, "invalid counter number (%d)\n", idx);
2456 return;
2457 }
2458
2459 spin_lock_irqsave(&pmu_lock, flags);
2460 val = xscale1pmu_read_pmnc();
2461 val &= ~mask;
2462 val |= evt;
2463 xscale1pmu_write_pmnc(val);
2464 spin_unlock_irqrestore(&pmu_lock, flags);
2465}
2466
2467static int
2468xscale1pmu_get_event_idx(struct cpu_hw_events *cpuc,
2469 struct hw_perf_event *event)
2470{
2471 if (XSCALE_PERFCTR_CCNT == event->config_base) {
2472 if (test_and_set_bit(XSCALE_CYCLE_COUNTER, cpuc->used_mask))
2473 return -EAGAIN;
2474
2475 return XSCALE_CYCLE_COUNTER;
2476 } else {
2477 if (!test_and_set_bit(XSCALE_COUNTER1, cpuc->used_mask)) {
2478 return XSCALE_COUNTER1;
2479 }
2480
2481 if (!test_and_set_bit(XSCALE_COUNTER0, cpuc->used_mask)) {
2482 return XSCALE_COUNTER0;
2483 }
2484
2485 return -EAGAIN;
2486 }
2487}
2488
2489static void
2490xscale1pmu_start(void)
2491{
2492 unsigned long flags, val;
2493
2494 spin_lock_irqsave(&pmu_lock, flags);
2495 val = xscale1pmu_read_pmnc();
2496 val |= XSCALE_PMU_ENABLE;
2497 xscale1pmu_write_pmnc(val);
2498 spin_unlock_irqrestore(&pmu_lock, flags);
2499}
2500
2501static void
2502xscale1pmu_stop(void)
2503{
2504 unsigned long flags, val;
2505
2506 spin_lock_irqsave(&pmu_lock, flags);
2507 val = xscale1pmu_read_pmnc();
2508 val &= ~XSCALE_PMU_ENABLE;
2509 xscale1pmu_write_pmnc(val);
2510 spin_unlock_irqrestore(&pmu_lock, flags);
2511}
2512
2513static inline u32
2514xscale1pmu_read_counter(int counter)
2515{
2516 u32 val = 0;
2517
2518 switch (counter) {
2519 case XSCALE_CYCLE_COUNTER:
2520 asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (val));
2521 break;
2522 case XSCALE_COUNTER0:
2523 asm volatile("mrc p14, 0, %0, c2, c0, 0" : "=r" (val));
2524 break;
2525 case XSCALE_COUNTER1:
2526 asm volatile("mrc p14, 0, %0, c3, c0, 0" : "=r" (val));
2527 break;
2528 }
2529
2530 return val;
2531}
2532
2533static inline void
2534xscale1pmu_write_counter(int counter, u32 val)
2535{
2536 switch (counter) {
2537 case XSCALE_CYCLE_COUNTER:
2538 asm volatile("mcr p14, 0, %0, c1, c0, 0" : : "r" (val));
2539 break;
2540 case XSCALE_COUNTER0:
2541 asm volatile("mcr p14, 0, %0, c2, c0, 0" : : "r" (val));
2542 break;
2543 case XSCALE_COUNTER1:
2544 asm volatile("mcr p14, 0, %0, c3, c0, 0" : : "r" (val));
2545 break;
2546 }
2547}
2548
2549static const struct arm_pmu xscale1pmu = {
2550 .id = ARM_PERF_PMU_ID_XSCALE1,
2551 .handle_irq = xscale1pmu_handle_irq,
2552 .enable = xscale1pmu_enable_event,
2553 .disable = xscale1pmu_disable_event,
2554 .event_map = xscalepmu_event_map,
2555 .raw_event = xscalepmu_raw_event,
2556 .read_counter = xscale1pmu_read_counter,
2557 .write_counter = xscale1pmu_write_counter,
2558 .get_event_idx = xscale1pmu_get_event_idx,
2559 .start = xscale1pmu_start,
2560 .stop = xscale1pmu_stop,
2561 .num_events = 3,
2562 .max_period = (1LLU << 32) - 1,
2563};
2564
2565#define XSCALE2_OVERFLOWED_MASK 0x01f
2566#define XSCALE2_CCOUNT_OVERFLOW 0x001
2567#define XSCALE2_COUNT0_OVERFLOW 0x002
2568#define XSCALE2_COUNT1_OVERFLOW 0x004
2569#define XSCALE2_COUNT2_OVERFLOW 0x008
2570#define XSCALE2_COUNT3_OVERFLOW 0x010
2571#define XSCALE2_CCOUNT_INT_EN 0x001
2572#define XSCALE2_COUNT0_INT_EN 0x002
2573#define XSCALE2_COUNT1_INT_EN 0x004
2574#define XSCALE2_COUNT2_INT_EN 0x008
2575#define XSCALE2_COUNT3_INT_EN 0x010
2576#define XSCALE2_COUNT0_EVT_SHFT 0
2577#define XSCALE2_COUNT0_EVT_MASK (0xff << XSCALE2_COUNT0_EVT_SHFT)
2578#define XSCALE2_COUNT1_EVT_SHFT 8
2579#define XSCALE2_COUNT1_EVT_MASK (0xff << XSCALE2_COUNT1_EVT_SHFT)
2580#define XSCALE2_COUNT2_EVT_SHFT 16
2581#define XSCALE2_COUNT2_EVT_MASK (0xff << XSCALE2_COUNT2_EVT_SHFT)
2582#define XSCALE2_COUNT3_EVT_SHFT 24
2583#define XSCALE2_COUNT3_EVT_MASK (0xff << XSCALE2_COUNT3_EVT_SHFT)
2584
2585static inline u32
2586xscale2pmu_read_pmnc(void)
2587{
2588 u32 val;
2589 asm volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (val));
2590 /* bits 1-2 and 4-23 are read-unpredictable */
2591 return val & 0xff000009;
2592}
2593
2594static inline void
2595xscale2pmu_write_pmnc(u32 val)
2596{
2597 /* bits 4-23 are write-as-0, 24-31 are write ignored */
2598 val &= 0xf;
2599 asm volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (val));
2600}
2601
2602static inline u32
2603xscale2pmu_read_overflow_flags(void)
2604{
2605 u32 val;
2606 asm volatile("mrc p14, 0, %0, c5, c1, 0" : "=r" (val));
2607 return val;
2608}
2609
2610static inline void
2611xscale2pmu_write_overflow_flags(u32 val)
2612{
2613 asm volatile("mcr p14, 0, %0, c5, c1, 0" : : "r" (val));
2614}
2615
2616static inline u32
2617xscale2pmu_read_event_select(void)
2618{
2619 u32 val;
2620 asm volatile("mrc p14, 0, %0, c8, c1, 0" : "=r" (val));
2621 return val;
2622}
2623
2624static inline void
2625xscale2pmu_write_event_select(u32 val)
2626{
2627 asm volatile("mcr p14, 0, %0, c8, c1, 0" : : "r"(val));
2628}
2629
2630static inline u32
2631xscale2pmu_read_int_enable(void)
2632{
2633 u32 val;
2634 asm volatile("mrc p14, 0, %0, c4, c1, 0" : "=r" (val));
2635 return val;
2636}
2637
2638static void
2639xscale2pmu_write_int_enable(u32 val)
2640{
2641 asm volatile("mcr p14, 0, %0, c4, c1, 0" : : "r" (val));
2642}
2643
2644static inline int
2645xscale2_pmnc_counter_has_overflowed(unsigned long of_flags,
2646 enum xscale_counters counter)
2647{
2648 int ret = 0;
2649
2650 switch (counter) {
2651 case XSCALE_CYCLE_COUNTER:
2652 ret = of_flags & XSCALE2_CCOUNT_OVERFLOW;
2653 break;
2654 case XSCALE_COUNTER0:
2655 ret = of_flags & XSCALE2_COUNT0_OVERFLOW;
2656 break;
2657 case XSCALE_COUNTER1:
2658 ret = of_flags & XSCALE2_COUNT1_OVERFLOW;
2659 break;
2660 case XSCALE_COUNTER2:
2661 ret = of_flags & XSCALE2_COUNT2_OVERFLOW;
2662 break;
2663 case XSCALE_COUNTER3:
2664 ret = of_flags & XSCALE2_COUNT3_OVERFLOW;
2665 break;
2666 default:
2667 WARN_ONCE(1, "invalid counter number (%d)\n", counter);
2668 }
2669
2670 return ret;
2671}
2672
2673static irqreturn_t
2674xscale2pmu_handle_irq(int irq_num, void *dev)
2675{
2676 unsigned long pmnc, of_flags;
2677 struct perf_sample_data data;
2678 struct cpu_hw_events *cpuc;
2679 struct pt_regs *regs;
2680 int idx;
2681
2682 /* Disable the PMU. */
2683 pmnc = xscale2pmu_read_pmnc();
2684 xscale2pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);
2685
2686 /* Check the overflow flag register. */
2687 of_flags = xscale2pmu_read_overflow_flags();
2688 if (!(of_flags & XSCALE2_OVERFLOWED_MASK))
2689 return IRQ_NONE;
2690
2691 /* Clear the overflow bits. */
2692 xscale2pmu_write_overflow_flags(of_flags);
2693
2694 regs = get_irq_regs();
2695
2696 perf_sample_data_init(&data, 0);
2697
2698 cpuc = &__get_cpu_var(cpu_hw_events);
2699 for (idx = 0; idx <= armpmu->num_events; ++idx) {
2700 struct perf_event *event = cpuc->events[idx];
2701 struct hw_perf_event *hwc;
2702
2703 if (!test_bit(idx, cpuc->active_mask))
2704 continue;
2705
2706 if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx))
2707 continue;
2708
2709 hwc = &event->hw;
2710 armpmu_event_update(event, hwc, idx);
2711 data.period = event->hw.last_period;
2712 if (!armpmu_event_set_period(event, hwc, idx))
2713 continue;
2714
2715 if (perf_event_overflow(event, 0, &data, regs))
2716 armpmu->disable(hwc, idx);
2717 }
2718
2719 perf_event_do_pending();
2720
2721 /*
2722 * Re-enable the PMU.
2723 */
2724 pmnc = xscale2pmu_read_pmnc() | XSCALE_PMU_ENABLE;
2725 xscale2pmu_write_pmnc(pmnc);
2726
2727 return IRQ_HANDLED;
2728}
2729
2730static void
2731xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
2732{
2733 unsigned long flags, ien, evtsel;
2734
2735 ien = xscale2pmu_read_int_enable();
2736 evtsel = xscale2pmu_read_event_select();
2737
2738 switch (idx) {
2739 case XSCALE_CYCLE_COUNTER:
2740 ien |= XSCALE2_CCOUNT_INT_EN;
2741 break;
2742 case XSCALE_COUNTER0:
2743 ien |= XSCALE2_COUNT0_INT_EN;
2744 evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
2745 evtsel |= hwc->config_base << XSCALE2_COUNT0_EVT_SHFT;
2746 break;
2747 case XSCALE_COUNTER1:
2748 ien |= XSCALE2_COUNT1_INT_EN;
2749 evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
2750 evtsel |= hwc->config_base << XSCALE2_COUNT1_EVT_SHFT;
2751 break;
2752 case XSCALE_COUNTER2:
2753 ien |= XSCALE2_COUNT2_INT_EN;
2754 evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
2755 evtsel |= hwc->config_base << XSCALE2_COUNT2_EVT_SHFT;
2756 break;
2757 case XSCALE_COUNTER3:
2758 ien |= XSCALE2_COUNT3_INT_EN;
2759 evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
2760 evtsel |= hwc->config_base << XSCALE2_COUNT3_EVT_SHFT;
2761 break;
2762 default:
2763 WARN_ONCE(1, "invalid counter number (%d)\n", idx);
2764 return;
2765 }
2766
2767 spin_lock_irqsave(&pmu_lock, flags);
2768 xscale2pmu_write_event_select(evtsel);
2769 xscale2pmu_write_int_enable(ien);
2770 spin_unlock_irqrestore(&pmu_lock, flags);
2771}
2772
2773static void
2774xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
2775{
2776 unsigned long flags, ien, evtsel;
2777
2778 ien = xscale2pmu_read_int_enable();
2779 evtsel = xscale2pmu_read_event_select();
2780
2781 switch (idx) {
2782 case XSCALE_CYCLE_COUNTER:
2783 ien &= ~XSCALE2_CCOUNT_INT_EN;
2784 break;
2785 case XSCALE_COUNTER0:
2786 ien &= ~XSCALE2_COUNT0_INT_EN;
2787 evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
2788 evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT0_EVT_SHFT;
2789 break;
2790 case XSCALE_COUNTER1:
2791 ien &= ~XSCALE2_COUNT1_INT_EN;
2792 evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
2793 evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT1_EVT_SHFT;
2794 break;
2795 case XSCALE_COUNTER2:
2796 ien &= ~XSCALE2_COUNT2_INT_EN;
2797 evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
2798 evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT2_EVT_SHFT;
2799 break;
2800 case XSCALE_COUNTER3:
2801 ien &= ~XSCALE2_COUNT3_INT_EN;
2802 evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
2803 evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT3_EVT_SHFT;
2804 break;
2805 default:
2806 WARN_ONCE(1, "invalid counter number (%d)\n", idx);
2807 return;
2808 }
2809
2810 spin_lock_irqsave(&pmu_lock, flags);
2811 xscale2pmu_write_event_select(evtsel);
2812 xscale2pmu_write_int_enable(ien);
2813 spin_unlock_irqrestore(&pmu_lock, flags);
2814}
2815
2816static int
2817xscale2pmu_get_event_idx(struct cpu_hw_events *cpuc,
2818 struct hw_perf_event *event)
2819{
2820 int idx = xscale1pmu_get_event_idx(cpuc, event);
2821 if (idx >= 0)
2822 goto out;
2823
2824 if (!test_and_set_bit(XSCALE_COUNTER3, cpuc->used_mask))
2825 idx = XSCALE_COUNTER3;
2826 else if (!test_and_set_bit(XSCALE_COUNTER2, cpuc->used_mask))
2827 idx = XSCALE_COUNTER2;
2828out:
2829 return idx;
2830}
2831
2832static void
2833xscale2pmu_start(void)
2834{
2835 unsigned long flags, val;
2836
2837 spin_lock_irqsave(&pmu_lock, flags);
2838 val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64;
2839 val |= XSCALE_PMU_ENABLE;
2840 xscale2pmu_write_pmnc(val);
2841 spin_unlock_irqrestore(&pmu_lock, flags);
2842}
2843
2844static void
2845xscale2pmu_stop(void)
2846{
2847 unsigned long flags, val;
2848
2849 spin_lock_irqsave(&pmu_lock, flags);
2850 val = xscale2pmu_read_pmnc();
2851 val &= ~XSCALE_PMU_ENABLE;
2852 xscale2pmu_write_pmnc(val);
2853 spin_unlock_irqrestore(&pmu_lock, flags);
2854}
2855
2856static inline u32
2857xscale2pmu_read_counter(int counter)
2858{
2859 u32 val = 0;
2860
2861 switch (counter) {
2862 case XSCALE_CYCLE_COUNTER:
2863 asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (val));
2864 break;
2865 case XSCALE_COUNTER0:
2866 asm volatile("mrc p14, 0, %0, c0, c2, 0" : "=r" (val));
2867 break;
2868 case XSCALE_COUNTER1:
2869 asm volatile("mrc p14, 0, %0, c1, c2, 0" : "=r" (val));
2870 break;
2871 case XSCALE_COUNTER2:
2872 asm volatile("mrc p14, 0, %0, c2, c2, 0" : "=r" (val));
2873 break;
2874 case XSCALE_COUNTER3:
2875 asm volatile("mrc p14, 0, %0, c3, c2, 0" : "=r" (val));
2876 break;
2877 }
2878
2879 return val;
2880}
2881
2882static inline void
2883xscale2pmu_write_counter(int counter, u32 val)
2884{
2885 switch (counter) {
2886 case XSCALE_CYCLE_COUNTER:
2887 asm volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (val));
2888 break;
2889 case XSCALE_COUNTER0:
2890 asm volatile("mcr p14, 0, %0, c0, c2, 0" : : "r" (val));
2891 break;
2892 case XSCALE_COUNTER1:
2893 asm volatile("mcr p14, 0, %0, c1, c2, 0" : : "r" (val));
2894 break;
2895 case XSCALE_COUNTER2:
2896 asm volatile("mcr p14, 0, %0, c2, c2, 0" : : "r" (val));
2897 break;
2898 case XSCALE_COUNTER3:
2899 asm volatile("mcr p14, 0, %0, c3, c2, 0" : : "r" (val));
2900 break;
2901 }
2902}
2903
2904static const struct arm_pmu xscale2pmu = {
2905 .id = ARM_PERF_PMU_ID_XSCALE2,
2906 .handle_irq = xscale2pmu_handle_irq,
2907 .enable = xscale2pmu_enable_event,
2908 .disable = xscale2pmu_disable_event,
2909 .event_map = xscalepmu_event_map,
2910 .raw_event = xscalepmu_raw_event,
2911 .read_counter = xscale2pmu_read_counter,
2912 .write_counter = xscale2pmu_write_counter,
2913 .get_event_idx = xscale2pmu_get_event_idx,
2914 .start = xscale2pmu_start,
2915 .stop = xscale2pmu_stop,
2916 .num_events = 5,
2917 .max_period = (1LLU << 32) - 1,
2918};
2919
2082static int __init 2920static int __init
2083init_hw_perf_events(void) 2921init_hw_perf_events(void)
2084{ 2922{
@@ -2086,7 +2924,7 @@ init_hw_perf_events(void)
2086 unsigned long implementor = (cpuid & 0xFF000000) >> 24; 2924 unsigned long implementor = (cpuid & 0xFF000000) >> 24;
2087 unsigned long part_number = (cpuid & 0xFFF0); 2925 unsigned long part_number = (cpuid & 0xFFF0);
2088 2926
2089 /* We only support ARM CPUs implemented by ARM at the moment. */ 2927 /* ARM Ltd CPUs. */
2090 if (0x41 == implementor) { 2928 if (0x41 == implementor) {
2091 switch (part_number) { 2929 switch (part_number) {
2092 case 0xB360: /* ARM1136 */ 2930 case 0xB360: /* ARM1136 */
@@ -2105,7 +2943,7 @@ init_hw_perf_events(void)
2105 perf_max_events = armv6mpcore_pmu.num_events; 2943 perf_max_events = armv6mpcore_pmu.num_events;
2106 break; 2944 break;
2107 case 0xC080: /* Cortex-A8 */ 2945 case 0xC080: /* Cortex-A8 */
2108 armv7pmu.name = ARMV7_PMU_CORTEX_A8_NAME; 2946 armv7pmu.id = ARM_PERF_PMU_ID_CA8;
2109 memcpy(armpmu_perf_cache_map, armv7_a8_perf_cache_map, 2947 memcpy(armpmu_perf_cache_map, armv7_a8_perf_cache_map,
2110 sizeof(armv7_a8_perf_cache_map)); 2948 sizeof(armv7_a8_perf_cache_map));
2111 armv7pmu.event_map = armv7_a8_pmu_event_map; 2949 armv7pmu.event_map = armv7_a8_pmu_event_map;
@@ -2117,7 +2955,7 @@ init_hw_perf_events(void)
2117 perf_max_events = armv7pmu.num_events; 2955 perf_max_events = armv7pmu.num_events;
2118 break; 2956 break;
2119 case 0xC090: /* Cortex-A9 */ 2957 case 0xC090: /* Cortex-A9 */
2120 armv7pmu.name = ARMV7_PMU_CORTEX_A9_NAME; 2958 armv7pmu.id = ARM_PERF_PMU_ID_CA9;
2121 memcpy(armpmu_perf_cache_map, armv7_a9_perf_cache_map, 2959 memcpy(armpmu_perf_cache_map, armv7_a9_perf_cache_map,
2122 sizeof(armv7_a9_perf_cache_map)); 2960 sizeof(armv7_a9_perf_cache_map));
2123 armv7pmu.event_map = armv7_a9_pmu_event_map; 2961 armv7pmu.event_map = armv7_a9_pmu_event_map;
@@ -2128,15 +2966,33 @@ init_hw_perf_events(void)
2128 armv7pmu.num_events = armv7_reset_read_pmnc(); 2966 armv7pmu.num_events = armv7_reset_read_pmnc();
2129 perf_max_events = armv7pmu.num_events; 2967 perf_max_events = armv7pmu.num_events;
2130 break; 2968 break;
2131 default: 2969 }
2132 pr_info("no hardware support available\n"); 2970 /* Intel CPUs [xscale]. */
2133 perf_max_events = -1; 2971 } else if (0x69 == implementor) {
2972 part_number = (cpuid >> 13) & 0x7;
2973 switch (part_number) {
2974 case 1:
2975 armpmu = &xscale1pmu;
2976 memcpy(armpmu_perf_cache_map, xscale_perf_cache_map,
2977 sizeof(xscale_perf_cache_map));
2978 perf_max_events = xscale1pmu.num_events;
2979 break;
2980 case 2:
2981 armpmu = &xscale2pmu;
2982 memcpy(armpmu_perf_cache_map, xscale_perf_cache_map,
2983 sizeof(xscale_perf_cache_map));
2984 perf_max_events = xscale2pmu.num_events;
2985 break;
2134 } 2986 }
2135 } 2987 }
2136 2988
2137 if (armpmu) 2989 if (armpmu) {
2138 pr_info("enabled with %s PMU driver, %d counters available\n", 2990 pr_info("enabled with %s PMU driver, %d counters available\n",
2139 armpmu->name, armpmu->num_events); 2991 arm_pmu_names[armpmu->id], armpmu->num_events);
2992 } else {
2993 pr_info("no hardware support available\n");
2994 perf_max_events = -1;
2995 }
2140 2996
2141 return 0; 2997 return 0;
2142} 2998}
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
index a124312e343f..b8af96ea62e6 100644
--- a/arch/arm/kernel/pmu.c
+++ b/arch/arm/kernel/pmu.c
@@ -2,6 +2,7 @@
2 * linux/arch/arm/kernel/pmu.c 2 * linux/arch/arm/kernel/pmu.c
3 * 3 *
4 * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles 4 * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
5 * Copyright (C) 2010 ARM Ltd, Will Deacon
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
@@ -9,65 +10,78 @@
9 * 10 *
10 */ 11 */
11 12
13#define pr_fmt(fmt) "PMU: " fmt
14
12#include <linux/cpumask.h> 15#include <linux/cpumask.h>
13#include <linux/err.h> 16#include <linux/err.h>
14#include <linux/interrupt.h> 17#include <linux/interrupt.h>
15#include <linux/kernel.h> 18#include <linux/kernel.h>
16#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/platform_device.h>
17 21
18#include <asm/pmu.h> 22#include <asm/pmu.h>
19 23
20/* 24static volatile long pmu_lock;
21 * Define the IRQs for the system. We could use something like a platform 25
22 * device but that seems fairly heavyweight for this. Also, the performance 26static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES];
23 * counters can't be removed or hotplugged. 27
24 * 28static int __devinit pmu_device_probe(struct platform_device *pdev)
25 * Ordering is important: init_pmu() will use the ordering to set the affinity 29{
26 * to the corresponding core. e.g. the first interrupt will go to cpu 0, the 30
27 * second goes to cpu 1 etc. 31 if (pdev->id < 0 || pdev->id >= ARM_NUM_PMU_DEVICES) {
28 */ 32 pr_warning("received registration request for unknown "
29static const int irqs[] = { 33 "device %d\n", pdev->id);
30#if defined(CONFIG_ARCH_OMAP2) 34 return -EINVAL;
31 3, 35 }
32#elif defined(CONFIG_ARCH_BCMRING) 36
33 IRQ_PMUIRQ, 37 if (pmu_devices[pdev->id])
34#elif defined(CONFIG_MACH_REALVIEW_EB) 38 pr_warning("registering new PMU device type %d overwrites "
35 IRQ_EB11MP_PMU_CPU0, 39 "previous registration!\n", pdev->id);
36 IRQ_EB11MP_PMU_CPU1, 40 else
37 IRQ_EB11MP_PMU_CPU2, 41 pr_info("registered new PMU device of type %d\n",
38 IRQ_EB11MP_PMU_CPU3, 42 pdev->id);
39#elif defined(CONFIG_ARCH_OMAP3)
40 INT_34XX_BENCH_MPU_EMUL,
41#elif defined(CONFIG_ARCH_IOP32X)
42 IRQ_IOP32X_CORE_PMU,
43#elif defined(CONFIG_ARCH_IOP33X)
44 IRQ_IOP33X_CORE_PMU,
45#elif defined(CONFIG_ARCH_PXA)
46 IRQ_PMU,
47#endif
48};
49 43
50static const struct pmu_irqs pmu_irqs = { 44 pmu_devices[pdev->id] = pdev;
51 .irqs = irqs, 45 return 0;
52 .num_irqs = ARRAY_SIZE(irqs), 46}
47
48static struct platform_driver pmu_driver = {
49 .driver = {
50 .name = "arm-pmu",
51 },
52 .probe = pmu_device_probe,
53}; 53};
54 54
55static volatile long pmu_lock; 55static int __init register_pmu_driver(void)
56{
57 return platform_driver_register(&pmu_driver);
58}
59device_initcall(register_pmu_driver);
56 60
57const struct pmu_irqs * 61struct platform_device *
58reserve_pmu(void) 62reserve_pmu(enum arm_pmu_type device)
59{ 63{
60 return test_and_set_bit_lock(0, &pmu_lock) ? ERR_PTR(-EBUSY) : 64 struct platform_device *pdev;
61 &pmu_irqs; 65
66 if (test_and_set_bit_lock(device, &pmu_lock)) {
67 pdev = ERR_PTR(-EBUSY);
68 } else if (pmu_devices[device] == NULL) {
69 clear_bit_unlock(device, &pmu_lock);
70 pdev = ERR_PTR(-ENODEV);
71 } else {
72 pdev = pmu_devices[device];
73 }
74
75 return pdev;
62} 76}
63EXPORT_SYMBOL_GPL(reserve_pmu); 77EXPORT_SYMBOL_GPL(reserve_pmu);
64 78
65int 79int
66release_pmu(const struct pmu_irqs *irqs) 80release_pmu(struct platform_device *pdev)
67{ 81{
68 if (WARN_ON(irqs != &pmu_irqs)) 82 if (WARN_ON(pdev != pmu_devices[pdev->id]))
69 return -EINVAL; 83 return -EINVAL;
70 clear_bit_unlock(0, &pmu_lock); 84 clear_bit_unlock(pdev->id, &pmu_lock);
71 return 0; 85 return 0;
72} 86}
73EXPORT_SYMBOL_GPL(release_pmu); 87EXPORT_SYMBOL_GPL(release_pmu);
@@ -87,17 +101,42 @@ set_irq_affinity(int irq,
87#endif 101#endif
88} 102}
89 103
90int 104static int
91init_pmu(void) 105init_cpu_pmu(void)
92{ 106{
93 int i, err = 0; 107 int i, err = 0;
108 struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU];
109
110 if (!pdev) {
111 err = -ENODEV;
112 goto out;
113 }
94 114
95 for (i = 0; i < pmu_irqs.num_irqs; ++i) { 115 for (i = 0; i < pdev->num_resources; ++i) {
96 err = set_irq_affinity(pmu_irqs.irqs[i], i); 116 err = set_irq_affinity(platform_get_irq(pdev, i), i);
97 if (err) 117 if (err)
98 break; 118 break;
99 } 119 }
100 120
121out:
122 return err;
123}
124
125int
126init_pmu(enum arm_pmu_type device)
127{
128 int err = 0;
129
130 switch (device) {
131 case ARM_PMU_DEVICE_CPU:
132 err = init_cpu_pmu();
133 break;
134 default:
135 pr_warning("attempt to initialise unknown device %d\n",
136 device);
137 err = -EINVAL;
138 }
139
101 return err; 140 return err;
102} 141}
103EXPORT_SYMBOL_GPL(init_pmu); 142EXPORT_SYMBOL_GPL(init_pmu);
diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile
index 88e31f549f50..e666eafed152 100644
--- a/arch/arm/oprofile/Makefile
+++ b/arch/arm/oprofile/Makefile
@@ -6,9 +6,4 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
6 oprofilefs.o oprofile_stats.o \ 6 oprofilefs.o oprofile_stats.o \
7 timer_int.o ) 7 timer_int.o )
8 8
9oprofile-y := $(DRIVER_OBJS) common.o backtrace.o 9oprofile-y := $(DRIVER_OBJS) common.o
10oprofile-$(CONFIG_CPU_XSCALE) += op_model_xscale.o
11oprofile-$(CONFIG_OPROFILE_ARM11_CORE) += op_model_arm11_core.o
12oprofile-$(CONFIG_OPROFILE_ARMV6) += op_model_v6.o
13oprofile-$(CONFIG_OPROFILE_MPCORE) += op_model_mpcore.o
14oprofile-$(CONFIG_OPROFILE_ARMV7) += op_model_v7.o
diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c
deleted file mode 100644
index d805a52b5032..000000000000
--- a/arch/arm/oprofile/backtrace.c
+++ /dev/null
@@ -1,83 +0,0 @@
1/*
2 * Arm specific backtracing code for oprofile
3 *
4 * Copyright 2005 Openedhand Ltd.
5 *
6 * Author: Richard Purdie <rpurdie@openedhand.com>
7 *
8 * Based on i386 oprofile backtrace code by John Levon, David Smith
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 */
15
16#include <linux/oprofile.h>
17#include <linux/sched.h>
18#include <linux/mm.h>
19#include <linux/uaccess.h>
20#include <asm/ptrace.h>
21#include <asm/stacktrace.h>
22
23static int report_trace(struct stackframe *frame, void *d)
24{
25 unsigned int *depth = d;
26
27 if (*depth) {
28 oprofile_add_trace(frame->pc);
29 (*depth)--;
30 }
31
32 return *depth == 0;
33}
34
35/*
36 * The registers we're interested in are at the end of the variable
37 * length saved register structure. The fp points at the end of this
38 * structure so the address of this struct is:
39 * (struct frame_tail *)(xxx->fp)-1
40 */
41struct frame_tail {
42 struct frame_tail *fp;
43 unsigned long sp;
44 unsigned long lr;
45} __attribute__((packed));
46
47static struct frame_tail* user_backtrace(struct frame_tail *tail)
48{
49 struct frame_tail buftail[2];
50
51 /* Also check accessibility of one struct frame_tail beyond */
52 if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
53 return NULL;
54 if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail)))
55 return NULL;
56
57 oprofile_add_trace(buftail[0].lr);
58
59 /* frame pointers should strictly progress back up the stack
60 * (towards higher addresses) */
61 if (tail >= buftail[0].fp)
62 return NULL;
63
64 return buftail[0].fp-1;
65}
66
67void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
68{
69 struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
70
71 if (!user_mode(regs)) {
72 struct stackframe frame;
73 frame.fp = regs->ARM_fp;
74 frame.sp = regs->ARM_sp;
75 frame.lr = regs->ARM_lr;
76 frame.pc = regs->ARM_pc;
77 walk_stackframe(&frame, report_trace, &depth);
78 return;
79 }
80
81 while (depth-- && tail && !((unsigned long) tail & 3))
82 tail = user_backtrace(tail);
83}
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 3fcd752d6146..0691176899ff 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -2,32 +2,184 @@
2 * @file common.c 2 * @file common.c
3 * 3 *
4 * @remark Copyright 2004 Oprofile Authors 4 * @remark Copyright 2004 Oprofile Authors
5 * @remark Copyright 2010 ARM Ltd.
5 * @remark Read the file COPYING 6 * @remark Read the file COPYING
6 * 7 *
7 * @author Zwane Mwaikambo 8 * @author Zwane Mwaikambo
9 * @author Will Deacon [move to perf]
8 */ 10 */
9 11
12#include <linux/cpumask.h>
13#include <linux/err.h>
14#include <linux/errno.h>
10#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/mutex.h>
11#include <linux/oprofile.h> 17#include <linux/oprofile.h>
12#include <linux/errno.h> 18#include <linux/perf_event.h>
19#include <linux/platform_device.h>
13#include <linux/slab.h> 20#include <linux/slab.h>
14#include <linux/sysdev.h> 21#include <asm/stacktrace.h>
15#include <linux/mutex.h> 22#include <linux/uaccess.h>
16 23
17#include "op_counter.h" 24#include <asm/perf_event.h>
18#include "op_arm_model.h" 25#include <asm/ptrace.h>
26
27#ifdef CONFIG_HW_PERF_EVENTS
28/*
29 * Per performance monitor configuration as set via oprofilefs.
30 */
31struct op_counter_config {
32 unsigned long count;
33 unsigned long enabled;
34 unsigned long event;
35 unsigned long unit_mask;
36 unsigned long kernel;
37 unsigned long user;
38 struct perf_event_attr attr;
39};
19 40
20static struct op_arm_model_spec *op_arm_model;
21static int op_arm_enabled; 41static int op_arm_enabled;
22static DEFINE_MUTEX(op_arm_mutex); 42static DEFINE_MUTEX(op_arm_mutex);
23 43
24struct op_counter_config *counter_config; 44static struct op_counter_config *counter_config;
45static struct perf_event **perf_events[nr_cpumask_bits];
46static int perf_num_counters;
47
48/*
49 * Overflow callback for oprofile.
50 */
51static void op_overflow_handler(struct perf_event *event, int unused,
52 struct perf_sample_data *data, struct pt_regs *regs)
53{
54 int id;
55 u32 cpu = smp_processor_id();
56
57 for (id = 0; id < perf_num_counters; ++id)
58 if (perf_events[cpu][id] == event)
59 break;
60
61 if (id != perf_num_counters)
62 oprofile_add_sample(regs, id);
63 else
64 pr_warning("oprofile: ignoring spurious overflow "
65 "on cpu %u\n", cpu);
66}
67
68/*
69 * Called by op_arm_setup to create perf attributes to mirror the oprofile
70 * settings in counter_config. Attributes are created as `pinned' events and
71 * so are permanently scheduled on the PMU.
72 */
73static void op_perf_setup(void)
74{
75 int i;
76 u32 size = sizeof(struct perf_event_attr);
77 struct perf_event_attr *attr;
78
79 for (i = 0; i < perf_num_counters; ++i) {
80 attr = &counter_config[i].attr;
81 memset(attr, 0, size);
82 attr->type = PERF_TYPE_RAW;
83 attr->size = size;
84 attr->config = counter_config[i].event;
85 attr->sample_period = counter_config[i].count;
86 attr->pinned = 1;
87 }
88}
89
90static int op_create_counter(int cpu, int event)
91{
92 int ret = 0;
93 struct perf_event *pevent;
94
95 if (!counter_config[event].enabled || (perf_events[cpu][event] != NULL))
96 return ret;
97
98 pevent = perf_event_create_kernel_counter(&counter_config[event].attr,
99 cpu, -1,
100 op_overflow_handler);
101
102 if (IS_ERR(pevent)) {
103 ret = PTR_ERR(pevent);
104 } else if (pevent->state != PERF_EVENT_STATE_ACTIVE) {
105 pr_warning("oprofile: failed to enable event %d "
106 "on CPU %d\n", event, cpu);
107 ret = -EBUSY;
108 } else {
109 perf_events[cpu][event] = pevent;
110 }
111
112 return ret;
113}
114
115static void op_destroy_counter(int cpu, int event)
116{
117 struct perf_event *pevent = perf_events[cpu][event];
118
119 if (pevent) {
120 perf_event_release_kernel(pevent);
121 perf_events[cpu][event] = NULL;
122 }
123}
124
125/*
126 * Called by op_arm_start to create active perf events based on the
127 * perviously configured attributes.
128 */
129static int op_perf_start(void)
130{
131 int cpu, event, ret = 0;
132
133 for_each_online_cpu(cpu) {
134 for (event = 0; event < perf_num_counters; ++event) {
135 ret = op_create_counter(cpu, event);
136 if (ret)
137 goto out;
138 }
139 }
140
141out:
142 return ret;
143}
144
145/*
146 * Called by op_arm_stop at the end of a profiling run.
147 */
148static void op_perf_stop(void)
149{
150 int cpu, event;
151
152 for_each_online_cpu(cpu)
153 for (event = 0; event < perf_num_counters; ++event)
154 op_destroy_counter(cpu, event);
155}
156
157
158static char *op_name_from_perf_id(enum arm_perf_pmu_ids id)
159{
160 switch (id) {
161 case ARM_PERF_PMU_ID_XSCALE1:
162 return "arm/xscale1";
163 case ARM_PERF_PMU_ID_XSCALE2:
164 return "arm/xscale2";
165 case ARM_PERF_PMU_ID_V6:
166 return "arm/armv6";
167 case ARM_PERF_PMU_ID_V6MP:
168 return "arm/mpcore";
169 case ARM_PERF_PMU_ID_CA8:
170 return "arm/armv7";
171 case ARM_PERF_PMU_ID_CA9:
172 return "arm/armv7-ca9";
173 default:
174 return NULL;
175 }
176}
25 177
26static int op_arm_create_files(struct super_block *sb, struct dentry *root) 178static int op_arm_create_files(struct super_block *sb, struct dentry *root)
27{ 179{
28 unsigned int i; 180 unsigned int i;
29 181
30 for (i = 0; i < op_arm_model->num_counters; i++) { 182 for (i = 0; i < perf_num_counters; i++) {
31 struct dentry *dir; 183 struct dentry *dir;
32 char buf[4]; 184 char buf[4];
33 185
@@ -46,12 +198,10 @@ static int op_arm_create_files(struct super_block *sb, struct dentry *root)
46 198
47static int op_arm_setup(void) 199static int op_arm_setup(void)
48{ 200{
49 int ret;
50
51 spin_lock(&oprofilefs_lock); 201 spin_lock(&oprofilefs_lock);
52 ret = op_arm_model->setup_ctrs(); 202 op_perf_setup();
53 spin_unlock(&oprofilefs_lock); 203 spin_unlock(&oprofilefs_lock);
54 return ret; 204 return 0;
55} 205}
56 206
57static int op_arm_start(void) 207static int op_arm_start(void)
@@ -60,8 +210,9 @@ static int op_arm_start(void)
60 210
61 mutex_lock(&op_arm_mutex); 211 mutex_lock(&op_arm_mutex);
62 if (!op_arm_enabled) { 212 if (!op_arm_enabled) {
63 ret = op_arm_model->start(); 213 ret = 0;
64 op_arm_enabled = !ret; 214 op_perf_start();
215 op_arm_enabled = 1;
65 } 216 }
66 mutex_unlock(&op_arm_mutex); 217 mutex_unlock(&op_arm_mutex);
67 return ret; 218 return ret;
@@ -71,113 +222,205 @@ static void op_arm_stop(void)
71{ 222{
72 mutex_lock(&op_arm_mutex); 223 mutex_lock(&op_arm_mutex);
73 if (op_arm_enabled) 224 if (op_arm_enabled)
74 op_arm_model->stop(); 225 op_perf_stop();
75 op_arm_enabled = 0; 226 op_arm_enabled = 0;
76 mutex_unlock(&op_arm_mutex); 227 mutex_unlock(&op_arm_mutex);
77} 228}
78 229
79#ifdef CONFIG_PM 230#ifdef CONFIG_PM
80static int op_arm_suspend(struct sys_device *dev, pm_message_t state) 231static int op_arm_suspend(struct platform_device *dev, pm_message_t state)
81{ 232{
82 mutex_lock(&op_arm_mutex); 233 mutex_lock(&op_arm_mutex);
83 if (op_arm_enabled) 234 if (op_arm_enabled)
84 op_arm_model->stop(); 235 op_perf_stop();
85 mutex_unlock(&op_arm_mutex); 236 mutex_unlock(&op_arm_mutex);
86 return 0; 237 return 0;
87} 238}
88 239
89static int op_arm_resume(struct sys_device *dev) 240static int op_arm_resume(struct platform_device *dev)
90{ 241{
91 mutex_lock(&op_arm_mutex); 242 mutex_lock(&op_arm_mutex);
92 if (op_arm_enabled && op_arm_model->start()) 243 if (op_arm_enabled && op_perf_start())
93 op_arm_enabled = 0; 244 op_arm_enabled = 0;
94 mutex_unlock(&op_arm_mutex); 245 mutex_unlock(&op_arm_mutex);
95 return 0; 246 return 0;
96} 247}
97 248
98static struct sysdev_class oprofile_sysclass = { 249static struct platform_driver oprofile_driver = {
99 .name = "oprofile", 250 .driver = {
251 .name = "arm-oprofile",
252 },
100 .resume = op_arm_resume, 253 .resume = op_arm_resume,
101 .suspend = op_arm_suspend, 254 .suspend = op_arm_suspend,
102}; 255};
103 256
104static struct sys_device device_oprofile = { 257static struct platform_device *oprofile_pdev;
105 .id = 0,
106 .cls = &oprofile_sysclass,
107};
108 258
109static int __init init_driverfs(void) 259static int __init init_driverfs(void)
110{ 260{
111 int ret; 261 int ret;
112 262
113 if (!(ret = sysdev_class_register(&oprofile_sysclass))) 263 ret = platform_driver_register(&oprofile_driver);
114 ret = sysdev_register(&device_oprofile); 264 if (ret)
265 goto out;
115 266
267 oprofile_pdev = platform_device_register_simple(
268 oprofile_driver.driver.name, 0, NULL, 0);
269 if (IS_ERR(oprofile_pdev)) {
270 ret = PTR_ERR(oprofile_pdev);
271 platform_driver_unregister(&oprofile_driver);
272 }
273
274out:
116 return ret; 275 return ret;
117} 276}
118 277
119static void exit_driverfs(void) 278static void exit_driverfs(void)
120{ 279{
121 sysdev_unregister(&device_oprofile); 280 platform_device_unregister(oprofile_pdev);
122 sysdev_class_unregister(&oprofile_sysclass); 281 platform_driver_unregister(&oprofile_driver);
123} 282}
124#else 283#else
125#define init_driverfs() do { } while (0) 284static int __init init_driverfs(void) { return 0; }
126#define exit_driverfs() do { } while (0) 285#define exit_driverfs() do { } while (0)
127#endif /* CONFIG_PM */ 286#endif /* CONFIG_PM */
128 287
129int __init oprofile_arch_init(struct oprofile_operations *ops) 288static int report_trace(struct stackframe *frame, void *d)
130{ 289{
131 struct op_arm_model_spec *spec = NULL; 290 unsigned int *depth = d;
132 int ret = -ENODEV;
133 291
134 ops->backtrace = arm_backtrace; 292 if (*depth) {
293 oprofile_add_trace(frame->pc);
294 (*depth)--;
295 }
135 296
136#ifdef CONFIG_CPU_XSCALE 297 return *depth == 0;
137 spec = &op_xscale_spec; 298}
138#endif
139 299
140#ifdef CONFIG_OPROFILE_ARMV6 300/*
141 spec = &op_armv6_spec; 301 * The registers we're interested in are at the end of the variable
142#endif 302 * length saved register structure. The fp points at the end of this
303 * structure so the address of this struct is:
304 * (struct frame_tail *)(xxx->fp)-1
305 */
306struct frame_tail {
307 struct frame_tail *fp;
308 unsigned long sp;
309 unsigned long lr;
310} __attribute__((packed));
143 311
144#ifdef CONFIG_OPROFILE_MPCORE 312static struct frame_tail* user_backtrace(struct frame_tail *tail)
145 spec = &op_mpcore_spec; 313{
146#endif 314 struct frame_tail buftail[2];
147 315
148#ifdef CONFIG_OPROFILE_ARMV7 316 /* Also check accessibility of one struct frame_tail beyond */
149 spec = &op_armv7_spec; 317 if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
150#endif 318 return NULL;
319 if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail)))
320 return NULL;
151 321
152 if (spec) { 322 oprofile_add_trace(buftail[0].lr);
153 ret = spec->init();
154 if (ret < 0)
155 return ret;
156 323
157 counter_config = kcalloc(spec->num_counters, sizeof(struct op_counter_config), 324 /* frame pointers should strictly progress back up the stack
158 GFP_KERNEL); 325 * (towards higher addresses) */
159 if (!counter_config) 326 if (tail >= buftail[0].fp)
160 return -ENOMEM; 327 return NULL;
161 328
162 op_arm_model = spec; 329 return buftail[0].fp-1;
163 init_driverfs(); 330}
164 ops->create_files = op_arm_create_files; 331
165 ops->setup = op_arm_setup; 332static void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
166 ops->shutdown = op_arm_stop; 333{
167 ops->start = op_arm_start; 334 struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
168 ops->stop = op_arm_stop; 335
169 ops->cpu_type = op_arm_model->name; 336 if (!user_mode(regs)) {
170 printk(KERN_INFO "oprofile: using %s\n", spec->name); 337 struct stackframe frame;
338 frame.fp = regs->ARM_fp;
339 frame.sp = regs->ARM_sp;
340 frame.lr = regs->ARM_lr;
341 frame.pc = regs->ARM_pc;
342 walk_stackframe(&frame, report_trace, &depth);
343 return;
171 } 344 }
172 345
346 while (depth-- && tail && !((unsigned long) tail & 3))
347 tail = user_backtrace(tail);
348}
349
350int __init oprofile_arch_init(struct oprofile_operations *ops)
351{
352 int cpu, ret = 0;
353
354 perf_num_counters = armpmu_get_max_events();
355
356 counter_config = kcalloc(perf_num_counters,
357 sizeof(struct op_counter_config), GFP_KERNEL);
358
359 if (!counter_config) {
360 pr_info("oprofile: failed to allocate %d "
361 "counters\n", perf_num_counters);
362 return -ENOMEM;
363 }
364
365 ret = init_driverfs();
366 if (ret) {
367 kfree(counter_config);
368 return ret;
369 }
370
371 for_each_possible_cpu(cpu) {
372 perf_events[cpu] = kcalloc(perf_num_counters,
373 sizeof(struct perf_event *), GFP_KERNEL);
374 if (!perf_events[cpu]) {
375 pr_info("oprofile: failed to allocate %d perf events "
376 "for cpu %d\n", perf_num_counters, cpu);
377 while (--cpu >= 0)
378 kfree(perf_events[cpu]);
379 return -ENOMEM;
380 }
381 }
382
383 ops->backtrace = arm_backtrace;
384 ops->create_files = op_arm_create_files;
385 ops->setup = op_arm_setup;
386 ops->start = op_arm_start;
387 ops->stop = op_arm_stop;
388 ops->shutdown = op_arm_stop;
389 ops->cpu_type = op_name_from_perf_id(armpmu_get_pmu_id());
390
391 if (!ops->cpu_type)
392 ret = -ENODEV;
393 else
394 pr_info("oprofile: using %s\n", ops->cpu_type);
395
173 return ret; 396 return ret;
174} 397}
175 398
176void oprofile_arch_exit(void) 399void oprofile_arch_exit(void)
177{ 400{
178 if (op_arm_model) { 401 int cpu, id;
402 struct perf_event *event;
403
404 if (*perf_events) {
179 exit_driverfs(); 405 exit_driverfs();
180 op_arm_model = NULL; 406 for_each_possible_cpu(cpu) {
407 for (id = 0; id < perf_num_counters; ++id) {
408 event = perf_events[cpu][id];
409 if (event != NULL)
410 perf_event_release_kernel(event);
411 }
412 kfree(perf_events[cpu]);
413 }
181 } 414 }
182 kfree(counter_config); 415
416 if (counter_config)
417 kfree(counter_config);
418}
419#else
420int __init oprofile_arch_init(struct oprofile_operations *ops)
421{
422 pr_info("oprofile: hardware counters not available\n");
423 return -ENODEV;
183} 424}
425void oprofile_arch_exit(void) {}
426#endif /* CONFIG_HW_PERF_EVENTS */
diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h
deleted file mode 100644
index 8c4e4f6a1de3..000000000000
--- a/arch/arm/oprofile/op_arm_model.h
+++ /dev/null
@@ -1,35 +0,0 @@
1/**
2 * @file op_arm_model.h
3 * interface to ARM machine specific operations
4 *
5 * @remark Copyright 2004 Oprofile Authors
6 * @remark Read the file COPYING
7 *
8 * @author Zwane Mwaikambo
9 */
10
11#ifndef OP_ARM_MODEL_H
12#define OP_ARM_MODEL_H
13
14struct op_arm_model_spec {
15 int (*init)(void);
16 unsigned int num_counters;
17 int (*setup_ctrs)(void);
18 int (*start)(void);
19 void (*stop)(void);
20 char *name;
21};
22
23#ifdef CONFIG_CPU_XSCALE
24extern struct op_arm_model_spec op_xscale_spec;
25#endif
26
27extern struct op_arm_model_spec op_armv6_spec;
28extern struct op_arm_model_spec op_mpcore_spec;
29extern struct op_arm_model_spec op_armv7_spec;
30
31extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
32
33extern int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec);
34extern void op_arm_exit(void);
35#endif /* OP_ARM_MODEL_H */
diff --git a/arch/arm/oprofile/op_counter.h b/arch/arm/oprofile/op_counter.h
deleted file mode 100644
index ca942a63b52f..000000000000
--- a/arch/arm/oprofile/op_counter.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/**
2 * @file op_counter.h
3 *
4 * @remark Copyright 2004 Oprofile Authors
5 * @remark Read the file COPYING
6 *
7 * @author Zwane Mwaikambo
8 */
9
10#ifndef OP_COUNTER_H
11#define OP_COUNTER_H
12
13/* Per performance monitor configuration as set via
14 * oprofilefs.
15 */
16struct op_counter_config {
17 unsigned long count;
18 unsigned long enabled;
19 unsigned long event;
20 unsigned long unit_mask;
21 unsigned long kernel;
22 unsigned long user;
23};
24
25extern struct op_counter_config *counter_config;
26
27#endif /* OP_COUNTER_H */
diff --git a/arch/arm/oprofile/op_model_arm11_core.c b/arch/arm/oprofile/op_model_arm11_core.c
deleted file mode 100644
index ef3e2653b90c..000000000000
--- a/arch/arm/oprofile/op_model_arm11_core.c
+++ /dev/null
@@ -1,162 +0,0 @@
1/**
2 * @file op_model_arm11_core.c
3 * ARM11 Event Monitor Driver
4 * @remark Copyright 2004 ARM SMP Development Team
5 */
6#include <linux/types.h>
7#include <linux/errno.h>
8#include <linux/oprofile.h>
9#include <linux/interrupt.h>
10#include <linux/irq.h>
11#include <linux/smp.h>
12
13#include "op_counter.h"
14#include "op_arm_model.h"
15#include "op_model_arm11_core.h"
16
17/*
18 * ARM11 PMU support
19 */
20static inline void arm11_write_pmnc(u32 val)
21{
22 /* upper 4bits and 7, 11 are write-as-0 */
23 val &= 0x0ffff77f;
24 asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
25}
26
27static inline u32 arm11_read_pmnc(void)
28{
29 u32 val;
30 asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
31 return val;
32}
33
34static void arm11_reset_counter(unsigned int cnt)
35{
36 u32 val = -(u32)counter_config[CPU_COUNTER(smp_processor_id(), cnt)].count;
37 switch (cnt) {
38 case CCNT:
39 asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
40 break;
41
42 case PMN0:
43 asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
44 break;
45
46 case PMN1:
47 asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
48 break;
49 }
50}
51
52int arm11_setup_pmu(void)
53{
54 unsigned int cnt;
55 u32 pmnc;
56
57 if (arm11_read_pmnc() & PMCR_E) {
58 printk(KERN_ERR "oprofile: CPU%u PMU still enabled when setup new event counter.\n", smp_processor_id());
59 return -EBUSY;
60 }
61
62 /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
63 arm11_write_pmnc(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
64 PMCR_C | PMCR_P);
65
66 for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
67 unsigned long event;
68
69 if (!counter_config[CPU_COUNTER(smp_processor_id(), cnt)].enabled)
70 continue;
71
72 event = counter_config[CPU_COUNTER(smp_processor_id(), cnt)].event & 255;
73
74 /*
75 * Set event (if destined for PMNx counters)
76 */
77 if (cnt == PMN0) {
78 pmnc |= event << 20;
79 } else if (cnt == PMN1) {
80 pmnc |= event << 12;
81 }
82
83 /*
84 * We don't need to set the event if it's a cycle count
85 * Enable interrupt for this counter
86 */
87 pmnc |= PMCR_IEN_PMN0 << cnt;
88 arm11_reset_counter(cnt);
89 }
90 arm11_write_pmnc(pmnc);
91
92 return 0;
93}
94
95int arm11_start_pmu(void)
96{
97 arm11_write_pmnc(arm11_read_pmnc() | PMCR_E);
98 return 0;
99}
100
101int arm11_stop_pmu(void)
102{
103 unsigned int cnt;
104
105 arm11_write_pmnc(arm11_read_pmnc() & ~PMCR_E);
106
107 for (cnt = PMN0; cnt <= CCNT; cnt++)
108 arm11_reset_counter(cnt);
109
110 return 0;
111}
112
113/*
114 * CPU counters' IRQ handler (one IRQ per CPU)
115 */
116static irqreturn_t arm11_pmu_interrupt(int irq, void *arg)
117{
118 struct pt_regs *regs = get_irq_regs();
119 unsigned int cnt;
120 u32 pmnc;
121
122 pmnc = arm11_read_pmnc();
123
124 for (cnt = PMN0; cnt <= CCNT; cnt++) {
125 if ((pmnc & (PMCR_OFL_PMN0 << cnt)) && (pmnc & (PMCR_IEN_PMN0 << cnt))) {
126 arm11_reset_counter(cnt);
127 oprofile_add_sample(regs, CPU_COUNTER(smp_processor_id(), cnt));
128 }
129 }
130 /* Clear counter flag(s) */
131 arm11_write_pmnc(pmnc);
132 return IRQ_HANDLED;
133}
134
135int arm11_request_interrupts(const int *irqs, int nr)
136{
137 unsigned int i;
138 int ret = 0;
139
140 for(i = 0; i < nr; i++) {
141 ret = request_irq(irqs[i], arm11_pmu_interrupt, IRQF_DISABLED, "CP15 PMU", NULL);
142 if (ret != 0) {
143 printk(KERN_ERR "oprofile: unable to request IRQ%u for MPCORE-EM\n",
144 irqs[i]);
145 break;
146 }
147 }
148
149 if (i != nr)
150 while (i-- != 0)
151 free_irq(irqs[i], NULL);
152
153 return ret;
154}
155
156void arm11_release_interrupts(const int *irqs, int nr)
157{
158 unsigned int i;
159
160 for (i = 0; i < nr; i++)
161 free_irq(irqs[i], NULL);
162}
diff --git a/arch/arm/oprofile/op_model_arm11_core.h b/arch/arm/oprofile/op_model_arm11_core.h
deleted file mode 100644
index 1902b99d9dfd..000000000000
--- a/arch/arm/oprofile/op_model_arm11_core.h
+++ /dev/null
@@ -1,45 +0,0 @@
1/**
2 * @file op_model_arm11_core.h
3 * ARM11 Event Monitor Driver
4 * @remark Copyright 2004 ARM SMP Development Team
5 * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
6 * @remark Copyright 2000-2004 MontaVista Software Inc
7 * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
8 * @remark Copyright 2004 Intel Corporation
9 * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
10 * @remark Copyright 2004 Oprofile Authors
11 *
12 * @remark Read the file COPYING
13 *
14 * @author Zwane Mwaikambo
15 */
16#ifndef OP_MODEL_ARM11_CORE_H
17#define OP_MODEL_ARM11_CORE_H
18
19/*
20 * Per-CPU PMCR
21 */
22#define PMCR_E (1 << 0) /* Enable */
23#define PMCR_P (1 << 1) /* Count reset */
24#define PMCR_C (1 << 2) /* Cycle counter reset */
25#define PMCR_D (1 << 3) /* Cycle counter counts every 64th cpu cycle */
26#define PMCR_IEN_PMN0 (1 << 4) /* Interrupt enable count reg 0 */
27#define PMCR_IEN_PMN1 (1 << 5) /* Interrupt enable count reg 1 */
28#define PMCR_IEN_CCNT (1 << 6) /* Interrupt enable cycle counter */
29#define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */
30#define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */
31#define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */
32
33#define PMN0 0
34#define PMN1 1
35#define CCNT 2
36
37#define CPU_COUNTER(cpu, counter) ((cpu) * 3 + (counter))
38
39int arm11_setup_pmu(void);
40int arm11_start_pmu(void);
41int arm11_stop_pmu(void);
42int arm11_request_interrupts(const int *, int);
43void arm11_release_interrupts(const int *, int);
44
45#endif
diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c
deleted file mode 100644
index f73ce875a395..000000000000
--- a/arch/arm/oprofile/op_model_mpcore.c
+++ /dev/null
@@ -1,306 +0,0 @@
1/**
2 * @file op_model_mpcore.c
3 * MPCORE Event Monitor Driver
4 * @remark Copyright 2004 ARM SMP Development Team
5 * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
6 * @remark Copyright 2000-2004 MontaVista Software Inc
7 * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
8 * @remark Copyright 2004 Intel Corporation
9 * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
10 * @remark Copyright 2004 Oprofile Authors
11 *
12 * @remark Read the file COPYING
13 *
14 * @author Zwane Mwaikambo
15 *
16 * Counters:
17 * 0: PMN0 on CPU0, per-cpu configurable event counter
18 * 1: PMN1 on CPU0, per-cpu configurable event counter
19 * 2: CCNT on CPU0
20 * 3: PMN0 on CPU1
21 * 4: PMN1 on CPU1
22 * 5: CCNT on CPU1
23 * 6: PMN0 on CPU1
24 * 7: PMN1 on CPU1
25 * 8: CCNT on CPU1
26 * 9: PMN0 on CPU1
27 * 10: PMN1 on CPU1
28 * 11: CCNT on CPU1
29 * 12-19: configurable SCU event counters
30 */
31
32/* #define DEBUG */
33#include <linux/types.h>
34#include <linux/errno.h>
35#include <linux/err.h>
36#include <linux/sched.h>
37#include <linux/oprofile.h>
38#include <linux/interrupt.h>
39#include <linux/smp.h>
40#include <linux/io.h>
41
42#include <asm/irq.h>
43#include <asm/mach/irq.h>
44#include <mach/hardware.h>
45#include <mach/board-eb.h>
46#include <asm/system.h>
47#include <asm/pmu.h>
48
49#include "op_counter.h"
50#include "op_arm_model.h"
51#include "op_model_arm11_core.h"
52#include "op_model_mpcore.h"
53
54/*
55 * MPCore SCU event monitor support
56 */
57#define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_EB11MP_SCU_BASE + 0x10)
58
59/*
60 * Bitmask of used SCU counters
61 */
62static unsigned int scu_em_used;
63static const struct pmu_irqs *pmu_irqs;
64
65/*
66 * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number)
67 */
68static inline void scu_reset_counter(struct eventmonitor __iomem *emc, unsigned int n)
69{
70 writel(-(u32)counter_config[SCU_COUNTER(n)].count, &emc->MC[n]);
71}
72
73static inline void scu_set_event(struct eventmonitor __iomem *emc, unsigned int n, u32 event)
74{
75 event &= 0xff;
76 writeb(event, &emc->MCEB[n]);
77}
78
79/*
80 * SCU counters' IRQ handler (one IRQ per counter => 2 IRQs per CPU)
81 */
82static irqreturn_t scu_em_interrupt(int irq, void *arg)
83{
84 struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
85 unsigned int cnt;
86
87 cnt = irq - IRQ_EB11MP_PMU_SCU0;
88 oprofile_add_sample(get_irq_regs(), SCU_COUNTER(cnt));
89 scu_reset_counter(emc, cnt);
90
91 /* Clear overflow flag for this counter */
92 writel(1 << (cnt + 16), &emc->PMCR);
93
94 return IRQ_HANDLED;
95}
96
97/* Configure just the SCU counters that the user has requested */
98static void scu_setup(void)
99{
100 struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
101 unsigned int i;
102
103 scu_em_used = 0;
104
105 for (i = 0; i < NUM_SCU_COUNTERS; i++) {
106 if (counter_config[SCU_COUNTER(i)].enabled &&
107 counter_config[SCU_COUNTER(i)].event) {
108 scu_set_event(emc, i, 0); /* disable counter for now */
109 scu_em_used |= 1 << i;
110 }
111 }
112}
113
114static int scu_start(void)
115{
116 struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
117 unsigned int temp, i;
118 unsigned long event;
119 int ret = 0;
120
121 /*
122 * request the SCU counter interrupts that we need
123 */
124 for (i = 0; i < NUM_SCU_COUNTERS; i++) {
125 if (scu_em_used & (1 << i)) {
126 ret = request_irq(IRQ_EB11MP_PMU_SCU0 + i, scu_em_interrupt, IRQF_DISABLED, "SCU PMU", NULL);
127 if (ret) {
128 printk(KERN_ERR "oprofile: unable to request IRQ%u for SCU Event Monitor\n",
129 IRQ_EB11MP_PMU_SCU0 + i);
130 goto err_free_scu;
131 }
132 }
133 }
134
135 /*
136 * clear overflow and enable interrupt for all used counters
137 */
138 temp = readl(&emc->PMCR);
139 for (i = 0; i < NUM_SCU_COUNTERS; i++) {
140 if (scu_em_used & (1 << i)) {
141 scu_reset_counter(emc, i);
142 event = counter_config[SCU_COUNTER(i)].event;
143 scu_set_event(emc, i, event);
144
145 /* clear overflow/interrupt */
146 temp |= 1 << (i + 16);
147 /* enable interrupt*/
148 temp |= 1 << (i + 8);
149 }
150 }
151
152 /* Enable all 8 counters */
153 temp |= PMCR_E;
154 writel(temp, &emc->PMCR);
155
156 return 0;
157
158 err_free_scu:
159 while (i--)
160 free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL);
161 return ret;
162}
163
164static void scu_stop(void)
165{
166 struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
167 unsigned int temp, i;
168
169 /* Disable counter interrupts */
170 /* Don't disable all 8 counters (with the E bit) as they may be in use */
171 temp = readl(&emc->PMCR);
172 for (i = 0; i < NUM_SCU_COUNTERS; i++) {
173 if (scu_em_used & (1 << i))
174 temp &= ~(1 << (i + 8));
175 }
176 writel(temp, &emc->PMCR);
177
178 /* Free counter interrupts and reset counters */
179 for (i = 0; i < NUM_SCU_COUNTERS; i++) {
180 if (scu_em_used & (1 << i)) {
181 scu_reset_counter(emc, i);
182 free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL);
183 }
184 }
185}
186
187struct em_function_data {
188 int (*fn)(void);
189 int ret;
190};
191
192static void em_func(void *data)
193{
194 struct em_function_data *d = data;
195 int ret = d->fn();
196 if (ret)
197 d->ret = ret;
198}
199
200static int em_call_function(int (*fn)(void))
201{
202 struct em_function_data data;
203
204 data.fn = fn;
205 data.ret = 0;
206
207 preempt_disable();
208 smp_call_function(em_func, &data, 1);
209 em_func(&data);
210 preempt_enable();
211
212 return data.ret;
213}
214
215/*
216 * Glue to stick the individual ARM11 PMUs and the SCU
217 * into the oprofile framework.
218 */
219static int em_setup_ctrs(void)
220{
221 int ret;
222
223 /* Configure CPU counters by cross-calling to the other CPUs */
224 ret = em_call_function(arm11_setup_pmu);
225 if (ret == 0)
226 scu_setup();
227
228 return 0;
229}
230
231static int em_start(void)
232{
233 int ret;
234
235 pmu_irqs = reserve_pmu();
236 if (IS_ERR(pmu_irqs)) {
237 ret = PTR_ERR(pmu_irqs);
238 goto out;
239 }
240
241 ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
242 if (ret == 0) {
243 em_call_function(arm11_start_pmu);
244
245 ret = scu_start();
246 if (ret) {
247 arm11_release_interrupts(pmu_irqs->irqs,
248 pmu_irqs->num_irqs);
249 } else {
250 release_pmu(pmu_irqs);
251 pmu_irqs = NULL;
252 }
253 }
254
255out:
256 return ret;
257}
258
259static void em_stop(void)
260{
261 em_call_function(arm11_stop_pmu);
262 arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
263 scu_stop();
264 release_pmu(pmu_irqs);
265}
266
267/*
268 * Why isn't there a function to route an IRQ to a specific CPU in
269 * genirq?
270 */
271static void em_route_irq(int irq, unsigned int cpu)
272{
273 struct irq_desc *desc = irq_desc + irq;
274 const struct cpumask *mask = cpumask_of(cpu);
275
276 spin_lock_irq(&desc->lock);
277 cpumask_copy(desc->affinity, mask);
278 desc->chip->set_affinity(irq, mask);
279 spin_unlock_irq(&desc->lock);
280}
281
282static int em_setup(void)
283{
284 /*
285 * Send SCU PMU interrupts to the "owner" CPU.
286 */
287 em_route_irq(IRQ_EB11MP_PMU_SCU0, 0);
288 em_route_irq(IRQ_EB11MP_PMU_SCU1, 0);
289 em_route_irq(IRQ_EB11MP_PMU_SCU2, 1);
290 em_route_irq(IRQ_EB11MP_PMU_SCU3, 1);
291 em_route_irq(IRQ_EB11MP_PMU_SCU4, 2);
292 em_route_irq(IRQ_EB11MP_PMU_SCU5, 2);
293 em_route_irq(IRQ_EB11MP_PMU_SCU6, 3);
294 em_route_irq(IRQ_EB11MP_PMU_SCU7, 3);
295
296 return init_pmu();
297}
298
299struct op_arm_model_spec op_mpcore_spec = {
300 .init = em_setup,
301 .num_counters = MPCORE_NUM_COUNTERS,
302 .setup_ctrs = em_setup_ctrs,
303 .start = em_start,
304 .stop = em_stop,
305 .name = "arm/mpcore",
306};
diff --git a/arch/arm/oprofile/op_model_mpcore.h b/arch/arm/oprofile/op_model_mpcore.h
deleted file mode 100644
index 73d811023688..000000000000
--- a/arch/arm/oprofile/op_model_mpcore.h
+++ /dev/null
@@ -1,61 +0,0 @@
1/**
2 * @file op_model_mpcore.c
3 * MPCORE Event Monitor Driver
4 * @remark Copyright 2004 ARM SMP Development Team
5 * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
6 * @remark Copyright 2000-2004 MontaVista Software Inc
7 * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
8 * @remark Copyright 2004 Intel Corporation
9 * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
10 * @remark Copyright 2004 Oprofile Authors
11 *
12 * @remark Read the file COPYING
13 *
14 * @author Zwane Mwaikambo
15 */
16#ifndef OP_MODEL_MPCORE_H
17#define OP_MODEL_MPCORE_H
18
19struct eventmonitor {
20 unsigned long PMCR;
21 unsigned char MCEB[8];
22 unsigned long MC[8];
23};
24
25/*
26 * List of userspace counter numbers: note that the structure is important.
27 * The code relies on CPUn's counters being CPU0's counters + 3n
28 * and on CPU0's counters starting at 0
29 */
30
31#define COUNTER_CPU0_PMN0 0
32#define COUNTER_CPU0_PMN1 1
33#define COUNTER_CPU0_CCNT 2
34
35#define COUNTER_CPU1_PMN0 3
36#define COUNTER_CPU1_PMN1 4
37#define COUNTER_CPU1_CCNT 5
38
39#define COUNTER_CPU2_PMN0 6
40#define COUNTER_CPU2_PMN1 7
41#define COUNTER_CPU2_CCNT 8
42
43#define COUNTER_CPU3_PMN0 9
44#define COUNTER_CPU3_PMN1 10
45#define COUNTER_CPU3_CCNT 11
46
47#define COUNTER_SCU_MN0 12
48#define COUNTER_SCU_MN1 13
49#define COUNTER_SCU_MN2 14
50#define COUNTER_SCU_MN3 15
51#define COUNTER_SCU_MN4 16
52#define COUNTER_SCU_MN5 17
53#define COUNTER_SCU_MN6 18
54#define COUNTER_SCU_MN7 19
55#define NUM_SCU_COUNTERS 8
56
57#define SCU_COUNTER(number) ((number) + COUNTER_SCU_MN0)
58
59#define MPCORE_NUM_COUNTERS SCU_COUNTER(NUM_SCU_COUNTERS)
60
61#endif
diff --git a/arch/arm/oprofile/op_model_v6.c b/arch/arm/oprofile/op_model_v6.c
deleted file mode 100644
index a22357a2fd08..000000000000
--- a/arch/arm/oprofile/op_model_v6.c
+++ /dev/null
@@ -1,78 +0,0 @@
1/**
2 * @file op_model_v6.c
3 * ARM11 Performance Monitor Driver
4 *
5 * Based on op_model_xscale.c
6 *
7 * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
8 * @remark Copyright 2000-2004 MontaVista Software Inc
9 * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
10 * @remark Copyright 2004 Intel Corporation
11 * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
12 * @remark Copyright 2004 OProfile Authors
13 *
14 * @remark Read the file COPYING
15 *
16 * @author Tony Lindgren <tony@atomide.com>
17 */
18
19/* #define DEBUG */
20#include <linux/types.h>
21#include <linux/errno.h>
22#include <linux/err.h>
23#include <linux/sched.h>
24#include <linux/oprofile.h>
25#include <linux/interrupt.h>
26#include <asm/irq.h>
27#include <asm/system.h>
28#include <asm/pmu.h>
29
30#include "op_counter.h"
31#include "op_arm_model.h"
32#include "op_model_arm11_core.h"
33
34static const struct pmu_irqs *pmu_irqs;
35
36static void armv6_pmu_stop(void)
37{
38 arm11_stop_pmu();
39 arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
40 release_pmu(pmu_irqs);
41 pmu_irqs = NULL;
42}
43
44static int armv6_pmu_start(void)
45{
46 int ret;
47
48 pmu_irqs = reserve_pmu();
49 if (IS_ERR(pmu_irqs)) {
50 ret = PTR_ERR(pmu_irqs);
51 goto out;
52 }
53
54 ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
55 if (ret >= 0) {
56 ret = arm11_start_pmu();
57 } else {
58 release_pmu(pmu_irqs);
59 pmu_irqs = NULL;
60 }
61
62out:
63 return ret;
64}
65
66static int armv6_detect_pmu(void)
67{
68 return 0;
69}
70
71struct op_arm_model_spec op_armv6_spec = {
72 .init = armv6_detect_pmu,
73 .num_counters = 3,
74 .setup_ctrs = arm11_setup_pmu,
75 .start = armv6_pmu_start,
76 .stop = armv6_pmu_stop,
77 .name = "arm/armv6",
78};
diff --git a/arch/arm/oprofile/op_model_v7.c b/arch/arm/oprofile/op_model_v7.c
deleted file mode 100644
index 8642d0891ae1..000000000000
--- a/arch/arm/oprofile/op_model_v7.c
+++ /dev/null
@@ -1,415 +0,0 @@
1/**
2 * op_model_v7.c
3 * ARM V7 (Cortex A8) Event Monitor Driver
4 *
5 * Copyright 2008 Jean Pihet <jpihet@mvista.com>
6 * Copyright 2004 ARM SMP Development Team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/types.h>
13#include <linux/errno.h>
14#include <linux/err.h>
15#include <linux/oprofile.h>
16#include <linux/interrupt.h>
17#include <linux/irq.h>
18#include <linux/smp.h>
19
20#include <asm/pmu.h>
21
22#include "op_counter.h"
23#include "op_arm_model.h"
24#include "op_model_v7.h"
25
26/* #define DEBUG */
27
28
29/*
30 * ARM V7 PMNC support
31 */
32
33static u32 cnt_en[CNTMAX];
34
35static inline void armv7_pmnc_write(u32 val)
36{
37 val &= PMNC_MASK;
38 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
39}
40
41static inline u32 armv7_pmnc_read(void)
42{
43 u32 val;
44
45 asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
46 return val;
47}
48
49static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
50{
51 u32 val;
52
53 if (cnt >= CNTMAX) {
54 printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter"
55 " %d\n", smp_processor_id(), cnt);
56 return -1;
57 }
58
59 if (cnt == CCNT)
60 val = CNTENS_C;
61 else
62 val = (1 << (cnt - CNT0));
63
64 val &= CNTENS_MASK;
65 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
66
67 return cnt;
68}
69
70static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
71{
72 u32 val;
73
74 if (cnt >= CNTMAX) {
75 printk(KERN_ERR "oprofile: CPU%u disabling wrong PMNC counter"
76 " %d\n", smp_processor_id(), cnt);
77 return -1;
78 }
79
80 if (cnt == CCNT)
81 val = CNTENC_C;
82 else
83 val = (1 << (cnt - CNT0));
84
85 val &= CNTENC_MASK;
86 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
87
88 return cnt;
89}
90
91static inline u32 armv7_pmnc_enable_intens(unsigned int cnt)
92{
93 u32 val;
94
95 if (cnt >= CNTMAX) {
96 printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter"
97 " interrupt enable %d\n", smp_processor_id(), cnt);
98 return -1;
99 }
100
101 if (cnt == CCNT)
102 val = INTENS_C;
103 else
104 val = (1 << (cnt - CNT0));
105
106 val &= INTENS_MASK;
107 asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
108
109 return cnt;
110}
111
112static inline u32 armv7_pmnc_getreset_flags(void)
113{
114 u32 val;
115
116 /* Read */
117 asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
118
119 /* Write to clear flags */
120 val &= FLAG_MASK;
121 asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val));
122
123 return val;
124}
125
126static inline int armv7_pmnc_select_counter(unsigned int cnt)
127{
128 u32 val;
129
130 if ((cnt == CCNT) || (cnt >= CNTMAX)) {
131 printk(KERN_ERR "oprofile: CPU%u selecting wrong PMNC counteri"
132 " %d\n", smp_processor_id(), cnt);
133 return -1;
134 }
135
136 val = (cnt - CNT0) & SELECT_MASK;
137 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
138
139 return cnt;
140}
141
142static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
143{
144 if (armv7_pmnc_select_counter(cnt) == cnt) {
145 val &= EVTSEL_MASK;
146 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
147 }
148}
149
150static void armv7_pmnc_reset_counter(unsigned int cnt)
151{
152 u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
153 u32 val = -(u32)counter_config[cpu_cnt].count;
154
155 switch (cnt) {
156 case CCNT:
157 armv7_pmnc_disable_counter(cnt);
158
159 asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
160
161 if (cnt_en[cnt] != 0)
162 armv7_pmnc_enable_counter(cnt);
163
164 break;
165
166 case CNT0:
167 case CNT1:
168 case CNT2:
169 case CNT3:
170 armv7_pmnc_disable_counter(cnt);
171
172 if (armv7_pmnc_select_counter(cnt) == cnt)
173 asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
174
175 if (cnt_en[cnt] != 0)
176 armv7_pmnc_enable_counter(cnt);
177
178 break;
179
180 default:
181 printk(KERN_ERR "oprofile: CPU%u resetting wrong PMNC counter"
182 " %d\n", smp_processor_id(), cnt);
183 break;
184 }
185}
186
187int armv7_setup_pmnc(void)
188{
189 unsigned int cnt;
190
191 if (armv7_pmnc_read() & PMNC_E) {
192 printk(KERN_ERR "oprofile: CPU%u PMNC still enabled when setup"
193 " new event counter.\n", smp_processor_id());
194 return -EBUSY;
195 }
196
197 /* Initialize & Reset PMNC: C bit and P bit */
198 armv7_pmnc_write(PMNC_P | PMNC_C);
199
200
201 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
202 unsigned long event;
203 u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
204
205 /*
206 * Disable counter
207 */
208 armv7_pmnc_disable_counter(cnt);
209 cnt_en[cnt] = 0;
210
211 if (!counter_config[cpu_cnt].enabled)
212 continue;
213
214 event = counter_config[cpu_cnt].event & 255;
215
216 /*
217 * Set event (if destined for PMNx counters)
218 * We don't need to set the event if it's a cycle count
219 */
220 if (cnt != CCNT)
221 armv7_pmnc_write_evtsel(cnt, event);
222
223 /*
224 * Enable interrupt for this counter
225 */
226 armv7_pmnc_enable_intens(cnt);
227
228 /*
229 * Reset counter
230 */
231 armv7_pmnc_reset_counter(cnt);
232
233 /*
234 * Enable counter
235 */
236 armv7_pmnc_enable_counter(cnt);
237 cnt_en[cnt] = 1;
238 }
239
240 return 0;
241}
242
243static inline void armv7_start_pmnc(void)
244{
245 armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
246}
247
248static inline void armv7_stop_pmnc(void)
249{
250 armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
251}
252
253/*
254 * CPU counters' IRQ handler (one IRQ per CPU)
255 */
256static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
257{
258 struct pt_regs *regs = get_irq_regs();
259 unsigned int cnt;
260 u32 flags;
261
262
263 /*
264 * Stop IRQ generation
265 */
266 armv7_stop_pmnc();
267
268 /*
269 * Get and reset overflow status flags
270 */
271 flags = armv7_pmnc_getreset_flags();
272
273 /*
274 * Cycle counter
275 */
276 if (flags & FLAG_C) {
277 u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), CCNT);
278 armv7_pmnc_reset_counter(CCNT);
279 oprofile_add_sample(regs, cpu_cnt);
280 }
281
282 /*
283 * PMNC counters 0:3
284 */
285 for (cnt = CNT0; cnt < CNTMAX; cnt++) {
286 if (flags & (1 << (cnt - CNT0))) {
287 u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
288 armv7_pmnc_reset_counter(cnt);
289 oprofile_add_sample(regs, cpu_cnt);
290 }
291 }
292
293 /*
294 * Allow IRQ generation
295 */
296 armv7_start_pmnc();
297
298 return IRQ_HANDLED;
299}
300
301int armv7_request_interrupts(const int *irqs, int nr)
302{
303 unsigned int i;
304 int ret = 0;
305
306 for (i = 0; i < nr; i++) {
307 ret = request_irq(irqs[i], armv7_pmnc_interrupt,
308 IRQF_DISABLED, "CP15 PMNC", NULL);
309 if (ret != 0) {
310 printk(KERN_ERR "oprofile: unable to request IRQ%u"
311 " for ARMv7\n",
312 irqs[i]);
313 break;
314 }
315 }
316
317 if (i != nr)
318 while (i-- != 0)
319 free_irq(irqs[i], NULL);
320
321 return ret;
322}
323
324void armv7_release_interrupts(const int *irqs, int nr)
325{
326 unsigned int i;
327
328 for (i = 0; i < nr; i++)
329 free_irq(irqs[i], NULL);
330}
331
332#ifdef DEBUG
333static void armv7_pmnc_dump_regs(void)
334{
335 u32 val;
336 unsigned int cnt;
337
338 printk(KERN_INFO "PMNC registers dump:\n");
339
340 asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
341 printk(KERN_INFO "PMNC =0x%08x\n", val);
342
343 asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val));
344 printk(KERN_INFO "CNTENS=0x%08x\n", val);
345
346 asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val));
347 printk(KERN_INFO "INTENS=0x%08x\n", val);
348
349 asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
350 printk(KERN_INFO "FLAGS =0x%08x\n", val);
351
352 asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val));
353 printk(KERN_INFO "SELECT=0x%08x\n", val);
354
355 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
356 printk(KERN_INFO "CCNT =0x%08x\n", val);
357
358 for (cnt = CNT0; cnt < CNTMAX; cnt++) {
359 armv7_pmnc_select_counter(cnt);
360 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
361 printk(KERN_INFO "CNT[%d] count =0x%08x\n", cnt-CNT0, val);
362 asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val));
363 printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n", cnt-CNT0, val);
364 }
365}
366#endif
367
368static const struct pmu_irqs *pmu_irqs;
369
370static void armv7_pmnc_stop(void)
371{
372#ifdef DEBUG
373 armv7_pmnc_dump_regs();
374#endif
375 armv7_stop_pmnc();
376 armv7_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
377 release_pmu(pmu_irqs);
378 pmu_irqs = NULL;
379}
380
381static int armv7_pmnc_start(void)
382{
383 int ret;
384
385 pmu_irqs = reserve_pmu();
386 if (IS_ERR(pmu_irqs))
387 return PTR_ERR(pmu_irqs);
388
389#ifdef DEBUG
390 armv7_pmnc_dump_regs();
391#endif
392 ret = armv7_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
393 if (ret >= 0) {
394 armv7_start_pmnc();
395 } else {
396 release_pmu(pmu_irqs);
397 pmu_irqs = NULL;
398 }
399
400 return ret;
401}
402
403static int armv7_detect_pmnc(void)
404{
405 return 0;
406}
407
408struct op_arm_model_spec op_armv7_spec = {
409 .init = armv7_detect_pmnc,
410 .num_counters = 5,
411 .setup_ctrs = armv7_setup_pmnc,
412 .start = armv7_pmnc_start,
413 .stop = armv7_pmnc_stop,
414 .name = "arm/armv7",
415};
diff --git a/arch/arm/oprofile/op_model_v7.h b/arch/arm/oprofile/op_model_v7.h
deleted file mode 100644
index 9ca334b39c75..000000000000
--- a/arch/arm/oprofile/op_model_v7.h
+++ /dev/null
@@ -1,103 +0,0 @@
1/**
2 * op_model_v7.h
3 * ARM v7 (Cortex A8) Event Monitor Driver
4 *
5 * Copyright 2008 Jean Pihet <jpihet@mvista.com>
6 * Copyright 2004 ARM SMP Development Team
7 * Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
8 * Copyright 2000-2004 MontaVista Software Inc
9 * Copyright 2004 Dave Jiang <dave.jiang@intel.com>
10 * Copyright 2004 Intel Corporation
11 * Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
12 * Copyright 2004 Oprofile Authors
13 *
14 * Read the file COPYING
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
19 */
20#ifndef OP_MODEL_V7_H
21#define OP_MODEL_V7_H
22
23/*
24 * Per-CPU PMNC: config reg
25 */
26#define PMNC_E (1 << 0) /* Enable all counters */
27#define PMNC_P (1 << 1) /* Reset all counters */
28#define PMNC_C (1 << 2) /* Cycle counter reset */
29#define PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */
30#define PMNC_X (1 << 4) /* Export to ETM */
31#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/
32#define PMNC_MASK 0x3f /* Mask for writable bits */
33
34/*
35 * Available counters
36 */
37#define CCNT 0
38#define CNT0 1
39#define CNT1 2
40#define CNT2 3
41#define CNT3 4
42#define CNTMAX 5
43
44#define CPU_COUNTER(cpu, counter) ((cpu) * CNTMAX + (counter))
45
46/*
47 * CNTENS: counters enable reg
48 */
49#define CNTENS_P0 (1 << 0)
50#define CNTENS_P1 (1 << 1)
51#define CNTENS_P2 (1 << 2)
52#define CNTENS_P3 (1 << 3)
53#define CNTENS_C (1 << 31)
54#define CNTENS_MASK 0x8000000f /* Mask for writable bits */
55
56/*
57 * CNTENC: counters disable reg
58 */
59#define CNTENC_P0 (1 << 0)
60#define CNTENC_P1 (1 << 1)
61#define CNTENC_P2 (1 << 2)
62#define CNTENC_P3 (1 << 3)
63#define CNTENC_C (1 << 31)
64#define CNTENC_MASK 0x8000000f /* Mask for writable bits */
65
66/*
67 * INTENS: counters overflow interrupt enable reg
68 */
69#define INTENS_P0 (1 << 0)
70#define INTENS_P1 (1 << 1)
71#define INTENS_P2 (1 << 2)
72#define INTENS_P3 (1 << 3)
73#define INTENS_C (1 << 31)
74#define INTENS_MASK 0x8000000f /* Mask for writable bits */
75
76/*
77 * EVTSEL: Event selection reg
78 */
79#define EVTSEL_MASK 0x7f /* Mask for writable bits */
80
81/*
82 * SELECT: Counter selection reg
83 */
84#define SELECT_MASK 0x1f /* Mask for writable bits */
85
86/*
87 * FLAG: counters overflow flag status reg
88 */
89#define FLAG_P0 (1 << 0)
90#define FLAG_P1 (1 << 1)
91#define FLAG_P2 (1 << 2)
92#define FLAG_P3 (1 << 3)
93#define FLAG_C (1 << 31)
94#define FLAG_MASK 0x8000000f /* Mask for writable bits */
95
96
97int armv7_setup_pmu(void);
98int armv7_start_pmu(void);
99int armv7_stop_pmu(void);
100int armv7_request_interrupts(const int *, int);
101void armv7_release_interrupts(const int *, int);
102
103#endif
diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c
deleted file mode 100644
index 1d34a02048bd..000000000000
--- a/arch/arm/oprofile/op_model_xscale.c
+++ /dev/null
@@ -1,444 +0,0 @@
1/**
2 * @file op_model_xscale.c
3 * XScale Performance Monitor Driver
4 *
5 * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
6 * @remark Copyright 2000-2004 MontaVista Software Inc
7 * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
8 * @remark Copyright 2004 Intel Corporation
9 * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
10 * @remark Copyright 2004 OProfile Authors
11 *
12 * @remark Read the file COPYING
13 *
14 * @author Zwane Mwaikambo
15 */
16
17/* #define DEBUG */
18#include <linux/types.h>
19#include <linux/errno.h>
20#include <linux/err.h>
21#include <linux/sched.h>
22#include <linux/oprofile.h>
23#include <linux/interrupt.h>
24#include <linux/irq.h>
25
26#include <asm/cputype.h>
27#include <asm/pmu.h>
28
29#include "op_counter.h"
30#include "op_arm_model.h"
31
32#define PMU_ENABLE 0x001 /* Enable counters */
33#define PMN_RESET 0x002 /* Reset event counters */
34#define CCNT_RESET 0x004 /* Reset clock counter */
35#define PMU_RESET (CCNT_RESET | PMN_RESET)
36#define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */
37
38/*
39 * Different types of events that can be counted by the XScale PMU
40 * as used by Oprofile userspace. Here primarily for documentation
41 * purposes.
42 */
43
44#define EVT_ICACHE_MISS 0x00
45#define EVT_ICACHE_NO_DELIVER 0x01
46#define EVT_DATA_STALL 0x02
47#define EVT_ITLB_MISS 0x03
48#define EVT_DTLB_MISS 0x04
49#define EVT_BRANCH 0x05
50#define EVT_BRANCH_MISS 0x06
51#define EVT_INSTRUCTION 0x07
52#define EVT_DCACHE_FULL_STALL 0x08
53#define EVT_DCACHE_FULL_STALL_CONTIG 0x09
54#define EVT_DCACHE_ACCESS 0x0A
55#define EVT_DCACHE_MISS 0x0B
56#define EVT_DCACE_WRITE_BACK 0x0C
57#define EVT_PC_CHANGED 0x0D
58#define EVT_BCU_REQUEST 0x10
59#define EVT_BCU_FULL 0x11
60#define EVT_BCU_DRAIN 0x12
61#define EVT_BCU_ECC_NO_ELOG 0x14
62#define EVT_BCU_1_BIT_ERR 0x15
63#define EVT_RMW 0x16
64/* EVT_CCNT is not hardware defined */
65#define EVT_CCNT 0xFE
66#define EVT_UNUSED 0xFF
67
68struct pmu_counter {
69 volatile unsigned long ovf;
70 unsigned long reset_counter;
71};
72
73enum { CCNT, PMN0, PMN1, PMN2, PMN3, MAX_COUNTERS };
74
75static struct pmu_counter results[MAX_COUNTERS];
76
77/*
78 * There are two versions of the PMU in current XScale processors
79 * with differing register layouts and number of performance counters.
80 * e.g. IOP32x is xsc1 whilst IOP33x is xsc2.
81 * We detect which register layout to use in xscale_detect_pmu()
82 */
83enum { PMU_XSC1, PMU_XSC2 };
84
85struct pmu_type {
86 int id;
87 char *name;
88 int num_counters;
89 unsigned int int_enable;
90 unsigned int cnt_ovf[MAX_COUNTERS];
91 unsigned int int_mask[MAX_COUNTERS];
92};
93
94static struct pmu_type pmu_parms[] = {
95 {
96 .id = PMU_XSC1,
97 .name = "arm/xscale1",
98 .num_counters = 3,
99 .int_mask = { [PMN0] = 0x10, [PMN1] = 0x20,
100 [CCNT] = 0x40 },
101 .cnt_ovf = { [CCNT] = 0x400, [PMN0] = 0x100,
102 [PMN1] = 0x200},
103 },
104 {
105 .id = PMU_XSC2,
106 .name = "arm/xscale2",
107 .num_counters = 5,
108 .int_mask = { [CCNT] = 0x01, [PMN0] = 0x02,
109 [PMN1] = 0x04, [PMN2] = 0x08,
110 [PMN3] = 0x10 },
111 .cnt_ovf = { [CCNT] = 0x01, [PMN0] = 0x02,
112 [PMN1] = 0x04, [PMN2] = 0x08,
113 [PMN3] = 0x10 },
114 },
115};
116
117static struct pmu_type *pmu;
118
119static void write_pmnc(u32 val)
120{
121 if (pmu->id == PMU_XSC1) {
122 /* upper 4bits and 7, 11 are write-as-0 */
123 val &= 0xffff77f;
124 __asm__ __volatile__ ("mcr p14, 0, %0, c0, c0, 0" : : "r" (val));
125 } else {
126 /* bits 4-23 are write-as-0, 24-31 are write ignored */
127 val &= 0xf;
128 __asm__ __volatile__ ("mcr p14, 0, %0, c0, c1, 0" : : "r" (val));
129 }
130}
131
132static u32 read_pmnc(void)
133{
134 u32 val;
135
136 if (pmu->id == PMU_XSC1)
137 __asm__ __volatile__ ("mrc p14, 0, %0, c0, c0, 0" : "=r" (val));
138 else {
139 __asm__ __volatile__ ("mrc p14, 0, %0, c0, c1, 0" : "=r" (val));
140 /* bits 1-2 and 4-23 are read-unpredictable */
141 val &= 0xff000009;
142 }
143
144 return val;
145}
146
147static u32 __xsc1_read_counter(int counter)
148{
149 u32 val = 0;
150
151 switch (counter) {
152 case CCNT:
153 __asm__ __volatile__ ("mrc p14, 0, %0, c1, c0, 0" : "=r" (val));
154 break;
155 case PMN0:
156 __asm__ __volatile__ ("mrc p14, 0, %0, c2, c0, 0" : "=r" (val));
157 break;
158 case PMN1:
159 __asm__ __volatile__ ("mrc p14, 0, %0, c3, c0, 0" : "=r" (val));
160 break;
161 }
162 return val;
163}
164
165static u32 __xsc2_read_counter(int counter)
166{
167 u32 val = 0;
168
169 switch (counter) {
170 case CCNT:
171 __asm__ __volatile__ ("mrc p14, 0, %0, c1, c1, 0" : "=r" (val));
172 break;
173 case PMN0:
174 __asm__ __volatile__ ("mrc p14, 0, %0, c0, c2, 0" : "=r" (val));
175 break;
176 case PMN1:
177 __asm__ __volatile__ ("mrc p14, 0, %0, c1, c2, 0" : "=r" (val));
178 break;
179 case PMN2:
180 __asm__ __volatile__ ("mrc p14, 0, %0, c2, c2, 0" : "=r" (val));
181 break;
182 case PMN3:
183 __asm__ __volatile__ ("mrc p14, 0, %0, c3, c2, 0" : "=r" (val));
184 break;
185 }
186 return val;
187}
188
189static u32 read_counter(int counter)
190{
191 u32 val;
192
193 if (pmu->id == PMU_XSC1)
194 val = __xsc1_read_counter(counter);
195 else
196 val = __xsc2_read_counter(counter);
197
198 return val;
199}
200
201static void __xsc1_write_counter(int counter, u32 val)
202{
203 switch (counter) {
204 case CCNT:
205 __asm__ __volatile__ ("mcr p14, 0, %0, c1, c0, 0" : : "r" (val));
206 break;
207 case PMN0:
208 __asm__ __volatile__ ("mcr p14, 0, %0, c2, c0, 0" : : "r" (val));
209 break;
210 case PMN1:
211 __asm__ __volatile__ ("mcr p14, 0, %0, c3, c0, 0" : : "r" (val));
212 break;
213 }
214}
215
216static void __xsc2_write_counter(int counter, u32 val)
217{
218 switch (counter) {
219 case CCNT:
220 __asm__ __volatile__ ("mcr p14, 0, %0, c1, c1, 0" : : "r" (val));
221 break;
222 case PMN0:
223 __asm__ __volatile__ ("mcr p14, 0, %0, c0, c2, 0" : : "r" (val));
224 break;
225 case PMN1:
226 __asm__ __volatile__ ("mcr p14, 0, %0, c1, c2, 0" : : "r" (val));
227 break;
228 case PMN2:
229 __asm__ __volatile__ ("mcr p14, 0, %0, c2, c2, 0" : : "r" (val));
230 break;
231 case PMN3:
232 __asm__ __volatile__ ("mcr p14, 0, %0, c3, c2, 0" : : "r" (val));
233 break;
234 }
235}
236
237static void write_counter(int counter, u32 val)
238{
239 if (pmu->id == PMU_XSC1)
240 __xsc1_write_counter(counter, val);
241 else
242 __xsc2_write_counter(counter, val);
243}
244
245static int xscale_setup_ctrs(void)
246{
247 u32 evtsel, pmnc;
248 int i;
249
250 for (i = CCNT; i < MAX_COUNTERS; i++) {
251 if (counter_config[i].enabled)
252 continue;
253
254 counter_config[i].event = EVT_UNUSED;
255 }
256
257 switch (pmu->id) {
258 case PMU_XSC1:
259 pmnc = (counter_config[PMN1].event << 20) | (counter_config[PMN0].event << 12);
260 pr_debug("xscale_setup_ctrs: pmnc: %#08x\n", pmnc);
261 write_pmnc(pmnc);
262 break;
263
264 case PMU_XSC2:
265 evtsel = counter_config[PMN0].event | (counter_config[PMN1].event << 8) |
266 (counter_config[PMN2].event << 16) | (counter_config[PMN3].event << 24);
267
268 pr_debug("xscale_setup_ctrs: evtsel %#08x\n", evtsel);
269 __asm__ __volatile__ ("mcr p14, 0, %0, c8, c1, 0" : : "r" (evtsel));
270 break;
271 }
272
273 for (i = CCNT; i < MAX_COUNTERS; i++) {
274 if (counter_config[i].event == EVT_UNUSED) {
275 counter_config[i].event = 0;
276 pmu->int_enable &= ~pmu->int_mask[i];
277 continue;
278 }
279
280 results[i].reset_counter = counter_config[i].count;
281 write_counter(i, -(u32)counter_config[i].count);
282 pmu->int_enable |= pmu->int_mask[i];
283 pr_debug("xscale_setup_ctrs: counter%d %#08x from %#08lx\n", i,
284 read_counter(i), counter_config[i].count);
285 }
286
287 return 0;
288}
289
290static void inline __xsc1_check_ctrs(void)
291{
292 int i;
293 u32 pmnc = read_pmnc();
294
295 /* NOTE: there's an A stepping errata that states if an overflow */
296 /* bit already exists and another occurs, the previous */
297 /* Overflow bit gets cleared. There's no workaround. */
298 /* Fixed in B stepping or later */
299
300 /* Write the value back to clear the overflow flags. Overflow */
301 /* flags remain in pmnc for use below */
302 write_pmnc(pmnc & ~PMU_ENABLE);
303
304 for (i = CCNT; i <= PMN1; i++) {
305 if (!(pmu->int_mask[i] & pmu->int_enable))
306 continue;
307
308 if (pmnc & pmu->cnt_ovf[i])
309 results[i].ovf++;
310 }
311}
312
313static void inline __xsc2_check_ctrs(void)
314{
315 int i;
316 u32 flag = 0, pmnc = read_pmnc();
317
318 pmnc &= ~PMU_ENABLE;
319 write_pmnc(pmnc);
320
321 /* read overflow flag register */
322 __asm__ __volatile__ ("mrc p14, 0, %0, c5, c1, 0" : "=r" (flag));
323
324 for (i = CCNT; i <= PMN3; i++) {
325 if (!(pmu->int_mask[i] & pmu->int_enable))
326 continue;
327
328 if (flag & pmu->cnt_ovf[i])
329 results[i].ovf++;
330 }
331
332 /* writeback clears overflow bits */
333 __asm__ __volatile__ ("mcr p14, 0, %0, c5, c1, 0" : : "r" (flag));
334}
335
336static irqreturn_t xscale_pmu_interrupt(int irq, void *arg)
337{
338 int i;
339 u32 pmnc;
340
341 if (pmu->id == PMU_XSC1)
342 __xsc1_check_ctrs();
343 else
344 __xsc2_check_ctrs();
345
346 for (i = CCNT; i < MAX_COUNTERS; i++) {
347 if (!results[i].ovf)
348 continue;
349
350 write_counter(i, -(u32)results[i].reset_counter);
351 oprofile_add_sample(get_irq_regs(), i);
352 results[i].ovf--;
353 }
354
355 pmnc = read_pmnc() | PMU_ENABLE;
356 write_pmnc(pmnc);
357
358 return IRQ_HANDLED;
359}
360
361static const struct pmu_irqs *pmu_irqs;
362
363static void xscale_pmu_stop(void)
364{
365 u32 pmnc = read_pmnc();
366
367 pmnc &= ~PMU_ENABLE;
368 write_pmnc(pmnc);
369
370 free_irq(pmu_irqs->irqs[0], results);
371 release_pmu(pmu_irqs);
372 pmu_irqs = NULL;
373}
374
375static int xscale_pmu_start(void)
376{
377 int ret;
378 u32 pmnc;
379
380 pmu_irqs = reserve_pmu();
381 if (IS_ERR(pmu_irqs))
382 return PTR_ERR(pmu_irqs);
383
384 pmnc = read_pmnc();
385
386 ret = request_irq(pmu_irqs->irqs[0], xscale_pmu_interrupt,
387 IRQF_DISABLED, "XScale PMU", (void *)results);
388
389 if (ret < 0) {
390 printk(KERN_ERR "oprofile: unable to request IRQ%d for XScale PMU\n",
391 pmu_irqs->irqs[0]);
392 release_pmu(pmu_irqs);
393 pmu_irqs = NULL;
394 return ret;
395 }
396
397 if (pmu->id == PMU_XSC1)
398 pmnc |= pmu->int_enable;
399 else {
400 __asm__ __volatile__ ("mcr p14, 0, %0, c4, c1, 0" : : "r" (pmu->int_enable));
401 pmnc &= ~PMU_CNT64;
402 }
403
404 pmnc |= PMU_ENABLE;
405 write_pmnc(pmnc);
406 pr_debug("xscale_pmu_start: pmnc: %#08x mask: %08x\n", pmnc, pmu->int_enable);
407 return 0;
408}
409
410static int xscale_detect_pmu(void)
411{
412 int ret = 0;
413 u32 id;
414
415 id = (read_cpuid(CPUID_ID) >> 13) & 0x7;
416
417 switch (id) {
418 case 1:
419 pmu = &pmu_parms[PMU_XSC1];
420 break;
421 case 2:
422 pmu = &pmu_parms[PMU_XSC2];
423 break;
424 default:
425 ret = -ENODEV;
426 break;
427 }
428
429 if (!ret) {
430 op_xscale_spec.name = pmu->name;
431 op_xscale_spec.num_counters = pmu->num_counters;
432 pr_debug("xscale_detect_pmu: detected %s PMU\n", pmu->name);
433 }
434
435 return ret;
436}
437
438struct op_arm_model_spec op_xscale_spec = {
439 .init = xscale_detect_pmu,
440 .setup_ctrs = xscale_setup_ctrs,
441 .start = xscale_pmu_start,
442 .stop = xscale_pmu_stop,
443};
444