1 /**
2 * Copyright (C) ARM Limited 2012. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
10 #if defined(__arm__) && (GATOR_PERF_PMU_SUPPORT)
11 #include <linux/platform_device.h>
12 #include <linux/interrupt.h>
13 #include <linux/irq.h>
15 #include <asm/pmu.h>
17 static DEFINE_MUTEX(perf_mutex);
19 extern int pmnc_counters;
20 extern int ccnt;
21 extern unsigned long pmnc_enabled[];
22 extern unsigned long pmnc_event[];
23 extern unsigned long pmnc_count[];
24 extern unsigned long pmnc_key[];
26 static DEFINE_PER_CPU(struct perf_event *, pevent);
27 static DEFINE_PER_CPU(struct perf_event_attr *, pevent_attr);
28 static DEFINE_PER_CPU(int, key);
29 static DEFINE_PER_CPU(unsigned int, prev_value);
31 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
32 static void ebs_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
33 #else
34 static void ebs_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
35 #endif
36 {
37 int cpu = smp_processor_id();
39 if (event != per_cpu(pevent, cpu))
40 return;
42 // Output backtrace
43 gator_add_sample(cpu, BACKTRACE_BUF, regs);
45 // Collect counters
46 collect_counters();
47 }
49 static void gator_event_sampling_online_dispatch(int cpu)
50 {
51 struct perf_event * ev;
53 if (!event_based_sampling)
54 return;
56 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
57 ev = per_cpu(pevent, cpu) = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler);
58 #else
59 ev = per_cpu(pevent, cpu) = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler, 0);
60 #endif
62 if (IS_ERR(ev)) {
63 pr_err("gator: unable to start event-based-sampling");
64 return;
65 }
67 if (ev->state != PERF_EVENT_STATE_ACTIVE) {
68 pr_err("gator: unable to start event-based-sampling");
69 perf_event_release_kernel(ev);
70 return;
71 }
73 ev->pmu->read(ev);
74 per_cpu(prev_value, cpu) = local64_read(&ev->count);
75 }
77 static void gator_event_sampling_offline_dispatch(int cpu)
78 {
79 struct perf_event * pe = NULL;
81 mutex_lock(&perf_mutex);
82 if (per_cpu(pevent, cpu)) {
83 pe = per_cpu(pevent, cpu);
84 per_cpu(pevent, cpu) = NULL;
85 }
86 mutex_unlock(&perf_mutex);
88 if (pe) {
89 perf_event_release_kernel(pe);
90 }
91 }
93 static int gator_event_sampling_start(void)
94 {
95 int cnt, event = 0, count = 0, ebs_key = 0, cpu;
97 for_each_present_cpu(cpu) {
98 per_cpu(pevent, cpu) = NULL;
99 per_cpu(pevent_attr, cpu) = NULL;
100 }
102 event_based_sampling = false;
103 for (cnt = 0; cnt < pmnc_counters; cnt++) {
104 if (pmnc_count[cnt] > 0) {
105 event_based_sampling = true;
106 event = pmnc_event[cnt];
107 count = pmnc_count[cnt];
108 ebs_key = pmnc_key[cnt];
109 break;
110 }
111 }
113 if (!event_based_sampling)
114 return 0;
116 for_each_present_cpu(cpu) {
117 u32 size = sizeof(struct perf_event_attr);
118 per_cpu(pevent_attr, cpu) = kmalloc(size, GFP_KERNEL);
119 if (!per_cpu(pevent_attr, cpu))
120 return -1;
122 memset(per_cpu(pevent_attr, cpu), 0, size);
123 per_cpu(pevent_attr, cpu)->type = PERF_TYPE_RAW;
124 per_cpu(pevent_attr, cpu)->size = size;
125 per_cpu(pevent_attr, cpu)->config = event;
126 per_cpu(pevent_attr, cpu)->sample_period = count;
127 per_cpu(pevent_attr, cpu)->pinned = 1;
129 // handle special case for ccnt
130 if (cnt == ccnt) {
131 per_cpu(pevent_attr, cpu)->type = PERF_TYPE_HARDWARE;
132 per_cpu(pevent_attr, cpu)->config = PERF_COUNT_HW_CPU_CYCLES;
133 }
135 per_cpu(key, cpu) = ebs_key;
136 }
138 return 0;
139 }
141 static void gator_event_sampling_stop(void)
142 {
143 int cpu;
145 for_each_present_cpu(cpu) {
146 if (per_cpu(pevent_attr, cpu)) {
147 kfree(per_cpu(pevent_attr, cpu));
148 per_cpu(pevent_attr, cpu) = NULL;
149 }
150 }
151 }
153 #else
154 static void gator_event_sampling_online_dispatch(int cpu) {}
155 static void gator_event_sampling_offline_dispatch(int cpu) {}
156 static int gator_event_sampling_start(void) {return 0;}
157 static void gator_event_sampling_stop(void) {}
158 #endif