1 /*
2 * Example events provider
3 *
4 * Copyright (C) ARM Limited 2010-2012. All rights reserved.
5 *
6 * 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 * published by the Free Software Foundation.
9 *
10 * Similar entries to those below must be present in the events.xml file.
11 * To add them to the events.xml, create an events-mmap.xml with the
12 * following contents and rebuild gatord:
13 *
14 * <counter_set name="mmaped_cntX">
15 * <counter name="mmaped_cnt0"/>
16 * <counter name="mmaped_cnt1"/>
17 * <counter name="mmaped_cnt2"/>
18 * </counter_set>
19 * <category name="mmaped" counter_set="mmaped_cntX" per_cpu="no">
20 * <event event="0x0" title="Simulated" name="Sine" display="maximum" average_selection="yes" description="Sort-of-sine"/>
21 * <event event="0x1" title="Simulated" name="Triangle" display="maximum" average_selection="yes" description="Triangular wave"/>
22 * <event event="0x2" title="Simulated" name="PWM" display="maximum" average_selection="yes" description="PWM Signal"/>
23 * </category>
24 */
26 #include <linux/init.h>
27 #include <linux/io.h>
28 #include <linux/ratelimit.h>
30 #include "gator.h"
32 #define MMAPED_COUNTERS_NUM 3
34 static struct {
35 unsigned long enabled;
36 unsigned long event;
37 unsigned long key;
38 } mmaped_counters[MMAPED_COUNTERS_NUM];
40 static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2];
42 #ifdef TODO
43 static void __iomem *mmaped_base;
44 #endif
46 #ifndef TODO
47 static s64 prev_time;
48 #endif
50 /* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/events */
51 static int gator_events_mmaped_create_files(struct super_block *sb,
52 struct dentry *root)
53 {
54 int i;
56 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
57 char buf[16];
58 struct dentry *dir;
60 snprintf(buf, sizeof(buf), "mmaped_cnt%d", i);
61 dir = gatorfs_mkdir(sb, root, buf);
62 if (WARN_ON(!dir))
63 return -1;
64 gatorfs_create_ulong(sb, dir, "enabled",
65 &mmaped_counters[i].enabled);
66 gatorfs_create_ulong(sb, dir, "event",
67 &mmaped_counters[i].event);
68 gatorfs_create_ro_ulong(sb, dir, "key",
69 &mmaped_counters[i].key);
70 }
72 return 0;
73 }
75 static int gator_events_mmaped_start(void)
76 {
77 #ifdef TODO
78 for (i = 0; i < MMAPED_COUNTERS_NUM; i++)
79 writel(mmaped_counters[i].event,
80 mmaped_base + COUNTERS_CONFIG_OFFSET[i]);
82 writel(ENABLED, COUNTERS_CONTROL_OFFSET);
83 #endif
85 #ifndef TODO
86 struct timespec ts;
87 getnstimeofday(&ts);
88 prev_time = timespec_to_ns(&ts);
89 #endif
91 return 0;
92 }
94 static void gator_events_mmaped_stop(void)
95 {
96 #ifdef TODO
97 writel(DISABLED, COUNTERS_CONTROL_OFFSET);
98 #endif
99 }
101 #ifndef TODO
102 /* This function "simulates" counters, generating values of fancy
103 * functions like sine or triangle... */
104 static int mmaped_simulate(int counter, int delta_in_us)
105 {
106 int result = 0;
108 switch (counter) {
109 case 0: /* sort-of-sine */
110 {
111 static int t = 0;
112 int x;
114 t += delta_in_us;
115 if (t > 2048000)
116 t = 0;
118 if (t % 1024000 < 512000)
119 x = 512000 - (t % 512000);
120 else
121 x = t % 512000;
123 result = 32 * x / 512000;
124 result = result * result;
126 if (t < 1024000)
127 result = 1922 - result;
128 }
129 break;
130 case 1: /* triangle */
131 {
132 static int v, d = 1;
134 v = v + d * delta_in_us;
135 if (v < 0) {
136 v = 0;
137 d = 1;
138 } else if (v > 1000000) {
139 v = 1000000;
140 d = -1;
141 }
143 result = v;
144 }
145 break;
146 case 2: /* PWM signal */
147 {
148 static int t, dc, x;
150 t += delta_in_us;
151 if (t > 1000000)
152 t = 0;
153 if (x / 1000000 != (x + delta_in_us) / 1000000)
154 dc = (dc + 100000) % 1000000;
155 x += delta_in_us;
157 result = t < dc ? 0 : 10;
158 }
159 break;
160 }
162 return result;
163 }
164 #endif
166 static int gator_events_mmaped_read(int **buffer)
167 {
168 int i;
169 int len = 0;
170 #ifndef TODO
171 int delta_in_us;
172 struct timespec ts;
173 s64 time;
174 #endif
176 /* System wide counters - read from one core only */
177 if (smp_processor_id())
178 return 0;
180 #ifndef TODO
181 getnstimeofday(&ts);
182 time = timespec_to_ns(&ts);
183 delta_in_us = (int)(time - prev_time) / 1000;
184 prev_time = time;
185 #endif
187 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
188 if (mmaped_counters[i].enabled) {
189 mmaped_buffer[len++] = mmaped_counters[i].key;
190 #ifdef TODO
191 mmaped_buffer[len++] = readl(mmaped_base +
192 COUNTERS_VALUE_OFFSET[i]);
193 #else
194 mmaped_buffer[len++] = mmaped_simulate(
195 mmaped_counters[i].event, delta_in_us);
196 #endif
197 }
198 }
200 if (buffer)
201 *buffer = mmaped_buffer;
203 return len;
204 }
206 static struct gator_interface gator_events_mmaped_interface = {
207 .create_files = gator_events_mmaped_create_files,
208 .start = gator_events_mmaped_start,
209 .stop = gator_events_mmaped_stop,
210 .read = gator_events_mmaped_read,
211 };
213 /* Must not be static! */
214 int __init gator_events_mmaped_init(void)
215 {
216 int i;
218 #ifdef TODO
219 mmaped_base = ioremap(COUNTERS_PHYS_ADDR, SZ_4K);
220 if (!mmaped_base)
221 return -ENOMEM;
222 #endif
224 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
225 mmaped_counters[i].enabled = 0;
226 mmaped_counters[i].key = gator_events_get_key();
227 }
229 return gator_events_install(&gator_events_mmaped_interface);
230 }
231 gator_events_init(gator_events_mmaped_init);