1 /**
2 * Copyright (C) ARM Limited 2010-2013. 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 */
9 #include "gator.h"
11 #include <linux/module.h>
12 #include <linux/time.h>
13 #include <linux/math64.h>
15 #include "linux/mali_linux_trace.h"
17 #include "gator_events_mali_common.h"
18 #include "gator_events_mali_4xx.h"
20 /*
21 * There are (currently) four different variants of the comms between gator and Mali:
22 * 1 (deprecated): No software counter support
23 * 2 (deprecated): Tracepoint called for each separate s/w counter value as it appears
24 * 3 (default): Single tracepoint for all s/w counters in a bundle.
25 * Interface style 3 is the default if no other is specified. 1 and 2 will be eliminated when
26 * existing Mali DDKs are upgraded.
27 * 4. As above, but for the Utgard (Mali-450) driver.
28 */
30 #if !defined(GATOR_MALI_INTERFACE_STYLE)
31 #define GATOR_MALI_INTERFACE_STYLE (3)
32 #endif
34 #if GATOR_MALI_INTERFACE_STYLE < 4
35 #include "mali/mali_mjollnir_profiling_gator_api.h"
36 #else
37 #include "mali/mali_utgard_profiling_gator_api.h"
38 #endif
40 /*
41 * Check that the MALI_SUPPORT define is set to one of the allowable device codes.
42 */
43 #if (MALI_SUPPORT != MALI_4xx)
44 #error MALI_SUPPORT set to an invalid device code: expecting MALI_4xx
45 #endif
47 /* gatorfs variables for counter enable state,
48 * the event the counter should count and the
49 * 'key' (a unique id set by gatord and returned
50 * by gator.ko)
51 */
52 static unsigned long counter_enabled[NUMBER_OF_EVENTS];
53 static unsigned long counter_event[NUMBER_OF_EVENTS];
54 static unsigned long counter_key[NUMBER_OF_EVENTS];
56 /* The data we have recorded */
57 static u32 counter_data[NUMBER_OF_EVENTS];
58 /* The address to sample (or 0 if samples are sent to us) */
59 static u32 *counter_address[NUMBER_OF_EVENTS];
61 /* An array used to return the data we recorded
62 * as key,value pairs hence the *2
63 */
64 static unsigned long counter_dump[NUMBER_OF_EVENTS * 2];
65 static unsigned long counter_prev[NUMBER_OF_EVENTS];
67 /* Note whether tracepoints have been registered */
68 static int trace_registered;
70 /*
71 * These numbers define the actual numbers of each block type that exist in the system. Initially
72 * these are set to the maxima defined above; if the driver is capable of being queried (newer
73 * drivers only) then the values may be revised.
74 */
75 static unsigned int n_vp_cores = MAX_NUM_VP_CORES;
76 static unsigned int n_l2_cores = MAX_NUM_L2_CACHE_CORES;
77 static unsigned int n_fp_cores = MAX_NUM_FP_CORES;
79 /**
80 * Calculate the difference and handle the overflow.
81 */
82 static u32 get_difference(u32 start, u32 end)
83 {
84 if (start - end >= 0) {
85 return start - end;
86 }
88 // Mali counters are unsigned 32 bit values that wrap.
89 return (4294967295u - end) + start;
90 }
92 /**
93 * Returns non-zero if the given counter ID is an activity counter.
94 */
95 static inline int is_activity_counter(unsigned int event_id)
96 {
97 return (event_id >= FIRST_ACTIVITY_EVENT &&
98 event_id <= LAST_ACTIVITY_EVENT);
99 }
101 /**
102 * Returns non-zero if the given counter ID is a hardware counter.
103 */
104 static inline int is_hw_counter(unsigned int event_id)
105 {
106 return (event_id >= FIRST_HW_COUNTER && event_id <= LAST_HW_COUNTER);
107 }
109 /*
110 * These are provided for utgard compatibility.
111 */
112 typedef void _mali_profiling_get_mali_version_type(struct _mali_profiling_mali_version *values);
113 typedef u32 _mali_profiling_get_l2_counters_type(_mali_profiling_l2_counter_values *values);
115 #if GATOR_MALI_INTERFACE_STYLE == 2
116 /**
117 * Returns non-zero if the given counter ID is a software counter.
118 */
119 static inline int is_sw_counter(unsigned int event_id)
120 {
121 return (event_id >= FIRST_SW_COUNTER && event_id <= LAST_SW_COUNTER);
122 }
123 #endif
125 #if GATOR_MALI_INTERFACE_STYLE == 2
126 /*
127 * The Mali DDK uses s64 types to contain software counter values, but gator
128 * can only use a maximum of 32 bits. This function scales a software counter
129 * to an appropriate range.
130 */
131 static u32 scale_sw_counter_value(unsigned int event_id, signed long long value)
132 {
133 u32 scaled_value;
135 switch (event_id) {
136 case COUNTER_GLES_UPLOAD_TEXTURE_TIME:
137 case COUNTER_GLES_UPLOAD_VBO_TIME:
138 scaled_value = (u32)div_s64(value, 1000000);
139 break;
140 default:
141 scaled_value = (u32)value;
142 break;
143 }
145 return scaled_value;
146 }
147 #endif
149 /* Probe for continuously sampled counter */
150 #if 0 //WE_DONT_CURRENTLY_USE_THIS_SO_SUPPRESS_WARNING
151 GATOR_DEFINE_PROBE(mali_sample_address, TP_PROTO(unsigned int event_id, u32 *addr))
152 {
153 /* Turning on too many pr_debug statements in frequently called functions
154 * can cause stability and/or performance problems
155 */
156 //pr_debug("gator: mali_sample_address %d %d\n", event_id, addr);
157 if (event_id >= ACTIVITY_VP && event_id <= COUNTER_FP3_C1) {
158 counter_address[event_id] = addr;
159 }
160 }
161 #endif
163 /* Probe for hardware counter events */
164 GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int value))
165 {
166 /* Turning on too many pr_debug statements in frequently called functions
167 * can cause stability and/or performance problems
168 */
169 //pr_debug("gator: mali_hw_counter %d %d\n", event_id, value);
170 if (is_hw_counter(event_id)) {
171 counter_data[event_id] = value;
172 }
173 }
175 #if GATOR_MALI_INTERFACE_STYLE == 2
176 GATOR_DEFINE_PROBE(mali_sw_counter, TP_PROTO(unsigned int event_id, signed long long value))
177 {
178 if (is_sw_counter(event_id)) {
179 counter_data[event_id] = scale_sw_counter_value(event_id, value);
180 }
181 }
182 #endif /* GATOR_MALI_INTERFACE_STYLE == 2 */
184 #if GATOR_MALI_INTERFACE_STYLE >= 3
185 GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surface_id, unsigned int *counters))
186 {
187 u32 i;
189 /* Copy over the values for those counters which are enabled. */
190 for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++) {
191 if (counter_enabled[i]) {
192 counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]);
193 }
194 }
195 }
196 #endif /* GATOR_MALI_INTERFACE_STYLE >= 3 */
198 /**
199 * Create a single filesystem entry for a specified event.
200 * @param sb the superblock
201 * @param root Filesystem root
202 * @param name The name of the entry to create
203 * @param event The ID of the event
204 * @param create_event_item boolean indicating whether to create an 'event' filesystem entry. True to create.
205 *
206 * @return 0 if ok, non-zero if the create failed.
207 */
208 static int create_fs_entry(struct super_block *sb, struct dentry *root, const char *name, int event, int create_event_item)
209 {
210 struct dentry *dir;
212 dir = gatorfs_mkdir(sb, root, name);
214 if (!dir) {
215 return -1;
216 }
218 if (create_event_item) {
219 gatorfs_create_ulong(sb, dir, "event", &counter_event[event]);
220 }
222 gatorfs_create_ulong(sb, dir, "enabled", &counter_enabled[event]);
223 gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]);
225 return 0;
226 }
228 #if GATOR_MALI_INTERFACE_STYLE > 3
229 /*
230 * Read the version info structure if available
231 */
232 static void initialise_version_info(void)
233 {
234 _mali_profiling_get_mali_version_type *mali_profiling_get_mali_version_symbol;
236 mali_profiling_get_mali_version_symbol = symbol_get(_mali_profiling_get_mali_version);
238 if (mali_profiling_get_mali_version_symbol) {
239 struct _mali_profiling_mali_version version_info;
241 pr_debug("gator: mali online _mali_profiling_get_mali_version symbol @ %p\n",
242 mali_profiling_get_mali_version_symbol);
244 /*
245 * Revise the number of each different core type using information derived from the DDK.
246 */
247 mali_profiling_get_mali_version_symbol(&version_info);
249 n_fp_cores = version_info.num_of_fp_cores;
250 n_vp_cores = version_info.num_of_vp_cores;
251 n_l2_cores = version_info.num_of_l2_cores;
253 /* Release the function - we're done with it. */
254 symbol_put(_mali_profiling_get_mali_version);
255 } else {
256 printk("gator: mali online _mali_profiling_get_mali_version symbol not found\n");
257 }
258 }
259 #endif
261 static int create_files(struct super_block *sb, struct dentry *root)
262 {
263 int event;
264 const char *mali_name = gator_mali_get_mali_name();
266 char buf[40];
267 int core_id;
268 int counter_number;
270 pr_debug("gator: Initialising counters with style = %d\n", GATOR_MALI_INTERFACE_STYLE);
272 #if GATOR_MALI_INTERFACE_STYLE > 3
273 /*
274 * Initialise first: this sets up the number of cores available (on compatible DDK versions).
275 * Ideally this would not need guarding but other parts of the code depend on the interface style being set
276 * correctly; if it is not then the system can enter an inconsistent state.
277 */
278 initialise_version_info();
279 #endif
281 /* Vertex processor counters */
282 for (core_id = 0; core_id < n_vp_cores; core_id++) {
283 int activity_counter_id = ACTIVITY_VP_0;
284 snprintf(buf, sizeof buf, "ARM_%s_VP_%d_active", mali_name, core_id);
285 if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) {
286 return -1;
287 }
289 for (counter_number = 0; counter_number < 2; counter_number++) {
290 int counter_id = COUNTER_VP_0_C0 + (2 * core_id) + counter_number;
292 snprintf(buf, sizeof buf, "ARM_%s_VP_%d_cnt%d", mali_name, core_id, counter_number);
293 if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
294 return -1;
295 }
296 }
297 }
299 /* Fragment processors' counters */
300 for (core_id = 0; core_id < n_fp_cores; core_id++) {
301 int activity_counter_id = ACTIVITY_FP_0 + core_id;
303 snprintf(buf, sizeof buf, "ARM_%s_FP_%d_active", mali_name, core_id);
304 if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) {
305 return -1;
306 }
308 for (counter_number = 0; counter_number < 2; counter_number++) {
309 int counter_id = COUNTER_FP_0_C0 + (2 * core_id) + counter_number;
311 snprintf(buf, sizeof buf, "ARM_%s_FP_%d_cnt%d", mali_name, core_id, counter_number);
312 if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
313 return -1;
314 }
315 }
316 }
318 /* L2 Cache counters */
319 for (core_id = 0; core_id < n_l2_cores; core_id++) {
320 for (counter_number = 0; counter_number < 2; counter_number++) {
321 int counter_id = COUNTER_L2_0_C0 + (2 * core_id) + counter_number;
323 snprintf(buf, sizeof buf, "ARM_%s_L2_%d_cnt%d", mali_name, core_id, counter_number);
324 if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
325 return -1;
326 }
327 }
328 }
330 /* Now set up the software counter entries */
331 for (event = FIRST_SW_COUNTER; event <= LAST_SW_COUNTER; event++) {
332 snprintf(buf, sizeof(buf), "ARM_%s_SW_%d", mali_name, event - FIRST_SW_COUNTER);
334 if (create_fs_entry(sb, root, buf, event, 0) != 0) {
335 return -1;
336 }
337 }
339 /* Now set up the special counter entries */
340 snprintf(buf, sizeof(buf), "ARM_%s_Filmstrip_cnt0", mali_name);
341 if (create_fs_entry(sb, root, buf, COUNTER_FILMSTRIP, 1) != 0) {
342 return -1;
343 }
345 #ifdef DVFS_REPORTED_BY_DDK
346 snprintf(buf, sizeof(buf), "ARM_%s_Frequency", mali_name);
347 if (create_fs_entry(sb, root, buf, COUNTER_FREQUENCY, 1) != 0) {
348 return -1;
349 }
351 snprintf(buf, sizeof(buf), "ARM_%s_Voltage", mali_name);
352 if (create_fs_entry(sb, root, buf, COUNTER_VOLTAGE, 1) != 0) {
353 return -1;
354 }
355 #endif
357 return 0;
358 }
360 /*
361 * Local store for the get_counters entry point into the DDK.
362 * This is stored here since it is used very regularly.
363 */
364 static mali_profiling_get_counters_type *mali_get_counters = NULL;
365 static _mali_profiling_get_l2_counters_type *mali_get_l2_counters = NULL;
367 /*
368 * Examine list of counters between two index limits and determine if any one is enabled.
369 * Returns 1 if any counter is enabled, 0 if none is.
370 */
371 static int is_any_counter_enabled(unsigned int first_counter, unsigned int last_counter)
372 {
373 unsigned int i;
375 for (i = first_counter; i <= last_counter; i++) {
376 if (counter_enabled[i]) {
377 return 1; /* At least one counter is enabled */
378 }
379 }
381 return 0; /* No s/w counters enabled */
382 }
384 static void init_counters(unsigned int from_counter, unsigned int to_counter)
385 {
386 unsigned int counter_id;
388 /* If a Mali driver is present and exporting the appropriate symbol
389 * then we can request the HW counters (of which there are only 2)
390 * be configured to count the desired events
391 */
392 mali_profiling_set_event_type *mali_set_hw_event;
394 mali_set_hw_event = symbol_get(_mali_profiling_set_event);
396 if (mali_set_hw_event) {
397 pr_debug("gator: mali online _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event);
399 for (counter_id = from_counter; counter_id <= to_counter; counter_id++) {
400 if (counter_enabled[counter_id]) {
401 mali_set_hw_event(counter_id, counter_event[counter_id]);
402 } else {
403 mali_set_hw_event(counter_id, 0xFFFFFFFF);
404 }
405 }
407 symbol_put(_mali_profiling_set_event);
408 } else {
409 printk("gator: mali online _mali_profiling_set_event symbol not found\n");
410 }
411 }
413 static void mali_counter_initialize(void)
414 {
415 int i;
416 int core_id;
418 mali_osk_fb_control_set_type *mali_set_fb_event;
419 mali_profiling_control_type *mali_control;
421 init_counters(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores) - 1);
422 init_counters(COUNTER_VP_0_C0, COUNTER_VP_0_C0 + (2 * n_vp_cores) - 1);
423 init_counters(COUNTER_FP_0_C0, COUNTER_FP_0_C0 + (2 * n_fp_cores) - 1);
425 mali_set_fb_event = symbol_get(_mali_osk_fb_control_set);
427 if (mali_set_fb_event) {
428 pr_debug("gator: mali online _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event);
430 mali_set_fb_event(0, (counter_enabled[COUNTER_FILMSTRIP] ? 1 : 0));
432 symbol_put(_mali_osk_fb_control_set);
433 } else {
434 printk("gator: mali online _mali_osk_fb_control_set symbol not found\n");
435 }
437 /* Generic control interface for Mali DDK. */
438 mali_control = symbol_get(_mali_profiling_control);
439 if (mali_control) {
440 /* The event attribute in the XML file keeps the actual frame rate. */
441 unsigned int rate = counter_event[COUNTER_FILMSTRIP] & 0xff;
442 unsigned int resize_factor = (counter_event[COUNTER_FILMSTRIP] >> 8) & 0xff;
444 pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control);
446 mali_control(SW_COUNTER_ENABLE, (is_any_counter_enabled(FIRST_SW_COUNTER, LAST_SW_COUNTER) ? 1 : 0));
447 mali_control(FBDUMP_CONTROL_ENABLE, (counter_enabled[COUNTER_FILMSTRIP] ? 1 : 0));
448 mali_control(FBDUMP_CONTROL_RATE, rate);
449 mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor);
451 pr_debug("gator: sent mali_control enabled=%d, rate=%d\n", (counter_enabled[COUNTER_FILMSTRIP] ? 1 : 0), rate);
453 symbol_put(_mali_profiling_control);
454 } else {
455 printk("gator: mali online _mali_profiling_control symbol not found\n");
456 }
458 mali_get_counters = symbol_get(_mali_profiling_get_counters);
459 if (mali_get_counters) {
460 pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", mali_get_counters);
462 } else {
463 pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined");
464 }
466 mali_get_l2_counters = symbol_get(_mali_profiling_get_l2_counters);
467 if (mali_get_l2_counters) {
468 pr_debug("gator: mali online _mali_profiling_get_l2_counters symbol @ %p\n", mali_get_l2_counters);
470 } else {
471 pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined");
472 }
474 if (!mali_get_counters && !mali_get_l2_counters) {
475 pr_debug("gator: WARNING: no L2 counters available");
476 n_l2_cores = 0;
477 }
479 for (core_id = 0; core_id < n_l2_cores; core_id++) {
480 int counter_id = COUNTER_L2_0_C0 + (2 * core_id);
481 counter_prev[counter_id] = 0;
482 counter_prev[counter_id + 1] = 0;
483 }
485 /* Clear counters in the start */
486 for (i = 0; i < NUMBER_OF_EVENTS; i++) {
487 counter_data[i] = 0;
488 }
489 }
491 static void mali_counter_deinitialize(void)
492 {
493 mali_profiling_set_event_type *mali_set_hw_event;
494 mali_osk_fb_control_set_type *mali_set_fb_event;
495 mali_profiling_control_type *mali_control;
497 mali_set_hw_event = symbol_get(_mali_profiling_set_event);
499 if (mali_set_hw_event) {
500 int i;
502 pr_debug("gator: mali offline _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event);
503 for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) {
504 mali_set_hw_event(i, 0xFFFFFFFF);
505 }
507 symbol_put(_mali_profiling_set_event);
508 } else {
509 printk("gator: mali offline _mali_profiling_set_event symbol not found\n");
510 }
512 mali_set_fb_event = symbol_get(_mali_osk_fb_control_set);
514 if (mali_set_fb_event) {
515 pr_debug("gator: mali offline _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event);
517 mali_set_fb_event(0, 0);
519 symbol_put(_mali_osk_fb_control_set);
520 } else {
521 printk("gator: mali offline _mali_osk_fb_control_set symbol not found\n");
522 }
524 /* Generic control interface for Mali DDK. */
525 mali_control = symbol_get(_mali_profiling_control);
527 if (mali_control) {
528 pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_set_fb_event);
530 /* Reset the DDK state - disable counter collection */
531 mali_control(SW_COUNTER_ENABLE, 0);
533 mali_control(FBDUMP_CONTROL_ENABLE, 0);
535 symbol_put(_mali_profiling_control);
536 } else {
537 printk("gator: mali offline _mali_profiling_control symbol not found\n");
538 }
540 if (mali_get_counters) {
541 symbol_put(_mali_profiling_get_counters);
542 }
544 if (mali_get_l2_counters) {
545 symbol_put(_mali_profiling_get_l2_counters);
546 }
547 }
549 static int start(void)
550 {
551 // register tracepoints
552 if (GATOR_REGISTER_TRACE(mali_hw_counter)) {
553 printk("gator: mali_hw_counter tracepoint failed to activate\n");
554 return -1;
555 }
557 #if GATOR_MALI_INTERFACE_STYLE == 1
558 /* None. */
559 #elif GATOR_MALI_INTERFACE_STYLE == 2
560 /* For patched Mali driver. */
561 if (GATOR_REGISTER_TRACE(mali_sw_counter)) {
562 printk("gator: mali_sw_counter tracepoint failed to activate\n");
563 return -1;
564 }
565 #elif GATOR_MALI_INTERFACE_STYLE >= 3
566 /* For Mali drivers with built-in support. */
567 if (GATOR_REGISTER_TRACE(mali_sw_counters)) {
568 printk("gator: mali_sw_counters tracepoint failed to activate\n");
569 return -1;
570 }
571 #else
572 #error Unknown GATOR_MALI_INTERFACE_STYLE option.
573 #endif
575 trace_registered = 1;
577 mali_counter_initialize();
578 return 0;
579 }
581 static void stop(void)
582 {
583 unsigned int cnt;
585 pr_debug("gator: mali stop\n");
587 if (trace_registered) {
588 GATOR_UNREGISTER_TRACE(mali_hw_counter);
590 #if GATOR_MALI_INTERFACE_STYLE == 1
591 /* None. */
592 #elif GATOR_MALI_INTERFACE_STYLE == 2
593 /* For patched Mali driver. */
594 GATOR_UNREGISTER_TRACE(mali_sw_counter);
595 #elif GATOR_MALI_INTERFACE_STYLE >= 3
596 /* For Mali drivers with built-in support. */
597 GATOR_UNREGISTER_TRACE(mali_sw_counters);
598 #else
599 #error Unknown GATOR_MALI_INTERFACE_STYLE option.
600 #endif
602 pr_debug("gator: mali timeline tracepoint deactivated\n");
604 trace_registered = 0;
605 }
607 for (cnt = 0; cnt < NUMBER_OF_EVENTS; cnt++) {
608 counter_enabled[cnt] = 0;
609 counter_event[cnt] = 0;
610 counter_address[cnt] = NULL;
611 }
613 mali_counter_deinitialize();
614 }
616 static void dump_counters(unsigned int from_counter, unsigned int to_counter, unsigned int *len)
617 {
618 unsigned int counter_id;
620 for (counter_id = from_counter; counter_id <= to_counter; counter_id++) {
621 if (counter_enabled[counter_id]) {
622 counter_dump[(*len)++] = counter_key[counter_id];
623 counter_dump[(*len)++] = counter_data[counter_id];
625 counter_data[counter_id] = 0;
626 }
627 }
628 }
630 static int read(int **buffer)
631 {
632 int len = 0;
634 if (!on_primary_core())
635 return 0;
637 // Read the L2 C0 and C1 here.
638 if (n_l2_cores > 0 && is_any_counter_enabled(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores))) {
639 unsigned int unavailable_l2_caches = 0;
640 _mali_profiling_l2_counter_values cache_values;
641 unsigned int cache_id;
642 struct _mali_profiling_core_counters *per_core;
644 /* Poke the driver to get the counter values - older style; only one L2 cache */
645 if (mali_get_l2_counters) {
646 unavailable_l2_caches = mali_get_l2_counters(&cache_values);
647 } else if (mali_get_counters) {
648 per_core = &cache_values.cores[0];
649 mali_get_counters(&per_core->source0, &per_core->value0, &per_core->source1, &per_core->value1);
650 } else {
651 /* This should never happen, as n_l2_caches is only set > 0 if one of the above functions is found. */
652 }
654 /* Fill in the two cache counter values for each cache block. */
655 for (cache_id = 0; cache_id < n_l2_cores; cache_id++) {
656 unsigned int counter_id_0 = COUNTER_L2_0_C0 + (2 * cache_id);
657 unsigned int counter_id_1 = counter_id_0 + 1;
659 if ((1 << cache_id) & unavailable_l2_caches) {
660 continue; /* This cache is unavailable (powered-off, possibly). */
661 }
663 per_core = &cache_values.cores[cache_id];
665 if (counter_enabled[counter_id_0]) {
666 // Calculate and save src0's counter val0
667 counter_dump[len++] = counter_key[counter_id_0];
668 counter_dump[len++] = get_difference(per_core->value0, counter_prev[counter_id_0]);
669 }
671 if (counter_enabled[counter_id_1]) {
672 // Calculate and save src1's counter val1
673 counter_dump[len++] = counter_key[counter_id_1];
674 counter_dump[len++] = get_difference(per_core->value1, counter_prev[counter_id_1]);
675 }
677 // Save the previous values for the counters.
678 counter_prev[counter_id_0] = per_core->value0;
679 counter_prev[counter_id_1] = per_core->value1;
680 }
681 }
683 /* Process other (non-timeline) counters. */
684 dump_counters(COUNTER_VP_0_C0, COUNTER_VP_0_C0 + (2 * n_vp_cores) - 1, &len);
685 dump_counters(COUNTER_FP_0_C0, COUNTER_FP_0_C0 + (2 * n_fp_cores) - 1, &len);
687 dump_counters(FIRST_SW_COUNTER, LAST_SW_COUNTER, &len);
689 #ifdef DVFS_REPORTED_BY_DDK
690 {
691 int cnt;
692 /*
693 * Add in the voltage and frequency counters if enabled. Note that, since these are
694 * actually passed as events, the counter value should not be cleared.
695 */
696 cnt = COUNTER_FREQUENCY;
697 if (counter_enabled[cnt]) {
698 counter_dump[len++] = counter_key[cnt];
699 counter_dump[len++] = counter_data[cnt];
700 }
702 cnt = COUNTER_VOLTAGE;
703 if (counter_enabled[cnt]) {
704 counter_dump[len++] = counter_key[cnt];
705 counter_dump[len++] = counter_data[cnt];
706 }
707 }
708 #endif
710 if (buffer) {
711 *buffer = (int *)counter_dump;
712 }
714 return len;
715 }
717 static struct gator_interface gator_events_mali_interface = {
718 .create_files = create_files,
719 .start = start,
720 .stop = stop,
721 .read = read,
722 };
724 extern void gator_events_mali_log_dvfs_event(unsigned int frequency_mhz, unsigned int voltage_mv)
725 {
726 #ifdef DVFS_REPORTED_BY_DDK
727 counter_data[COUNTER_FREQUENCY] = frequency_mhz;
728 counter_data[COUNTER_VOLTAGE] = voltage_mv;
729 #endif
730 }
732 int gator_events_mali_init(void)
733 {
734 unsigned int cnt;
736 pr_debug("gator: mali init\n");
738 for (cnt = 0; cnt < NUMBER_OF_EVENTS; cnt++) {
739 counter_enabled[cnt] = 0;
740 counter_event[cnt] = 0;
741 counter_key[cnt] = gator_events_get_key();
742 counter_address[cnt] = NULL;
743 counter_data[cnt] = 0;
744 }
746 trace_registered = 0;
748 return gator_events_install(&gator_events_mali_interface);
749 }
751 gator_events_init(gator_events_mali_init);