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_cnt" count="3"/>
15 * <category name="mmaped" counter_set="mmaped_cnt" per_cpu="no">
16 * <event event="0x0" title="Simulated" name="Sine" display="maximum" average_selection="yes" description="Sort-of-sine"/>
17 * <event event="0x1" title="Simulated" name="Triangle" display="maximum" average_selection="yes" description="Triangular wave"/>
18 * <event event="0x2" title="Simulated" name="PWM" display="maximum" average_selection="yes" description="PWM Signal"/>
19 * </category>
20 */
22 #include <linux/init.h>
23 #include <linux/io.h>
24 #include <linux/ratelimit.h>
26 #include "gator.h"
28 #define MMAPED_COUNTERS_NUM 3
30 static struct {
31 unsigned long enabled;
32 unsigned long event;
33 unsigned long key;
34 } mmaped_counters[MMAPED_COUNTERS_NUM];
36 static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2];
38 #ifdef TODO
39 static void __iomem *mmaped_base;
40 #endif
42 #ifndef TODO
43 static s64 prev_time;
44 #endif
46 /* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/events */
47 static int gator_events_mmaped_create_files(struct super_block *sb,
48 struct dentry *root)
49 {
50 int i;
52 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
53 char buf[16];
54 struct dentry *dir;
56 snprintf(buf, sizeof(buf), "mmaped_cnt%d", i);
57 dir = gatorfs_mkdir(sb, root, buf);
58 if (WARN_ON(!dir))
59 return -1;
60 gatorfs_create_ulong(sb, dir, "enabled",
61 &mmaped_counters[i].enabled);
62 gatorfs_create_ulong(sb, dir, "event",
63 &mmaped_counters[i].event);
64 gatorfs_create_ro_ulong(sb, dir, "key",
65 &mmaped_counters[i].key);
66 }
68 return 0;
69 }
71 static int gator_events_mmaped_start(void)
72 {
73 #ifdef TODO
74 for (i = 0; i < MMAPED_COUNTERS_NUM; i++)
75 writel(mmaped_counters[i].event,
76 mmaped_base + COUNTERS_CONFIG_OFFSET[i]);
78 writel(ENABLED, COUNTERS_CONTROL_OFFSET);
79 #endif
81 #ifndef TODO
82 struct timespec ts;
83 getnstimeofday(&ts);
84 prev_time = timespec_to_ns(&ts);
85 #endif
87 return 0;
88 }
90 static void gator_events_mmaped_stop(void)
91 {
92 #ifdef TODO
93 writel(DISABLED, COUNTERS_CONTROL_OFFSET);
94 #endif
95 }
97 #ifndef TODO
98 /* This function "simulates" counters, generating values of fancy
99 * functions like sine or triangle... */
100 static int mmaped_simulate(int counter, int delta_in_us)
101 {
102 int result = 0;
104 switch (counter) {
105 case 0: /* sort-of-sine */
106 {
107 static int t = 0;
108 int x;
110 t += delta_in_us;
111 if (t > 2048000)
112 t = 0;
114 if (t % 1024000 < 512000)
115 x = 512000 - (t % 512000);
116 else
117 x = t % 512000;
119 result = 32 * x / 512000;
120 result = result * result;
122 if (t < 1024000)
123 result = 1922 - result;
124 }
125 break;
126 case 1: /* triangle */
127 {
128 static int v, d = 1;
130 v = v + d * delta_in_us;
131 if (v < 0) {
132 v = 0;
133 d = 1;
134 } else if (v > 1000000) {
135 v = 1000000;
136 d = -1;
137 }
139 result = v;
140 }
141 break;
142 case 2: /* PWM signal */
143 {
144 static int t, dc, x;
146 t += delta_in_us;
147 if (t > 1000000)
148 t = 0;
149 if (x / 1000000 != (x + delta_in_us) / 1000000)
150 dc = (dc + 100000) % 1000000;
151 x += delta_in_us;
153 result = t < dc ? 0 : 10;
154 }
155 break;
156 }
158 return result;
159 }
160 #endif
162 static int gator_events_mmaped_read(int **buffer)
163 {
164 int i;
165 int len = 0;
166 #ifndef TODO
167 int delta_in_us;
168 struct timespec ts;
169 s64 time;
170 #endif
172 /* System wide counters - read from one core only */
173 if (smp_processor_id())
174 return 0;
176 #ifndef TODO
177 getnstimeofday(&ts);
178 time = timespec_to_ns(&ts);
179 delta_in_us = (int)(time - prev_time) / 1000;
180 prev_time = time;
181 #endif
183 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
184 if (mmaped_counters[i].enabled) {
185 mmaped_buffer[len++] = mmaped_counters[i].key;
186 #ifdef TODO
187 mmaped_buffer[len++] = readl(mmaped_base +
188 COUNTERS_VALUE_OFFSET[i]);
189 #else
190 mmaped_buffer[len++] = mmaped_simulate(
191 mmaped_counters[i].event, delta_in_us);
192 #endif
193 }
194 }
196 if (buffer)
197 *buffer = mmaped_buffer;
199 return len;
200 }
202 static struct gator_interface gator_events_mmaped_interface = {
203 .create_files = gator_events_mmaped_create_files,
204 .start = gator_events_mmaped_start,
205 .stop = gator_events_mmaped_stop,
206 .read = gator_events_mmaped_read,
207 };
209 /* Must not be static! */
210 int __init gator_events_mmaped_init(void)
211 {
212 int i;
214 #ifdef TODO
215 mmaped_base = ioremap(COUNTERS_PHYS_ADDR, SZ_4K);
216 if (!mmaped_base)
217 return -ENOMEM;
218 #endif
220 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
221 mmaped_counters[i].enabled = 0;
222 mmaped_counters[i].key = gator_events_get_key();
223 }
225 return gator_events_install(&gator_events_mmaped_interface);
226 }
227 gator_events_init(gator_events_mmaped_init);