]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/arm-ds5-gator.git/blob - driver/gator_trace_power.c
gator: Use device-tree when available for address of pl310 cache
[android-sdk/arm-ds5-gator.git] / driver / gator_trace_power.c
1 /**
2  * Copyright (C) ARM Limited 2011-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  *
8  */
10 #include <linux/cpufreq.h>
11 #include <trace/events/power.h>
13 #if defined(__arm__)
15 #include <asm/mach-types.h>
17 #define implements_wfi() (!machine_is_omap3_beagle())
19 #else
21 #define implements_wfi() false
23 #endif
25 // cpu_frequency and cpu_idle trace points were introduced in Linux kernel v2.6.38
26 // the now deprecated power_frequency trace point was available prior to 2.6.38, but only for x86
27 #if GATOR_CPU_FREQ_SUPPORT
28 enum {
29         POWER_CPU_FREQ,
30         POWER_CPU_IDLE,
31         POWER_TOTAL
32 };
34 static DEFINE_PER_CPU(ulong, idle_prev_state);
35 static ulong power_cpu_enabled[POWER_TOTAL];
36 static ulong power_cpu_key[POWER_TOTAL];
38 static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root)
39 {
40         struct dentry *dir;
41         int cpu;
42         bool found_nonzero_freq = false;
44         // Even if CONFIG_CPU_FREQ is defined, it still may not be used. Check
45         // for non-zero values from cpufreq_quick_get
46         for_each_online_cpu(cpu) {
47                 if (cpufreq_quick_get(cpu) > 0) {
48                         found_nonzero_freq = true;
49                         break;
50                 }
51         }
53         if (found_nonzero_freq) {
54                 // cpu_frequency
55                 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq");
56                 if (!dir) {
57                         return -1;
58                 }
59                 gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]);
60                 gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]);
61         }
63         // cpu_idle
64         dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle");
65         if (!dir) {
66                 return -1;
67         }
68         gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_IDLE]);
69         gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_IDLE]);
71         return 0;
72 }
74 // 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change
75 GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu))
76 {
77         cpu = lcpu_to_pcpu(cpu);
78         marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], frequency * 1000);
79 }
81 GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu))
82 {
83         cpu = lcpu_to_pcpu(cpu);
85         if (state == per_cpu(idle_prev_state, cpu)) {
86                 return;
87         }
89         if (implements_wfi()) {
90                 if (state == PWR_EVENT_EXIT) {
91                         // transition from wfi to non-wfi
92                         marshal_idle(cpu, MESSAGE_IDLE_EXIT);
93                 } else {
94                         // transition from non-wfi to wfi
95                         marshal_idle(cpu, MESSAGE_IDLE_ENTER);
96                 }
97         }
99         per_cpu(idle_prev_state, cpu) = state;
101         if (power_cpu_enabled[POWER_CPU_IDLE]) {
102                 // Increment state so that no negative numbers are sent
103                 marshal_event_single(cpu, power_cpu_key[POWER_CPU_IDLE], state + 1);
104         }
107 static void gator_trace_power_online(void)
109         int pcpu = get_physical_cpu();
110         int lcpu = get_logical_cpu();
111         if (power_cpu_enabled[POWER_CPU_FREQ]) {
112                 marshal_event_single(pcpu, power_cpu_key[POWER_CPU_FREQ], cpufreq_quick_get(lcpu) * 1000);
113         }
116 static void gator_trace_power_offline(void)
118         // Set frequency to zero on an offline
119         int cpu = get_physical_cpu();
120         if (power_cpu_enabled[POWER_CPU_FREQ]) {
121                 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], 0);
122         }
125 static int gator_trace_power_start(void)
127         int cpu;
129         // register tracepoints
130         if (power_cpu_enabled[POWER_CPU_FREQ])
131                 if (GATOR_REGISTER_TRACE(cpu_frequency))
132                         goto fail_cpu_frequency_exit;
134         // Always register for cpu:idle for detecting WFI, independent of power_cpu_enabled[POWER_CPU_IDLE]
135         if (GATOR_REGISTER_TRACE(cpu_idle))
136                 goto fail_cpu_idle_exit;
137         pr_debug("gator: registered power event tracepoints\n");
139         for_each_present_cpu(cpu) {
140                 per_cpu(idle_prev_state, cpu) = 0;
141         }
143         return 0;
145         // unregister tracepoints on error
146 fail_cpu_idle_exit:
147         if (power_cpu_enabled[POWER_CPU_FREQ])
148                 GATOR_UNREGISTER_TRACE(cpu_frequency);
149 fail_cpu_frequency_exit:
150         pr_err("gator: power event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
152         return -1;
155 static void gator_trace_power_stop(void)
157         int i;
159         if (power_cpu_enabled[POWER_CPU_FREQ])
160                 GATOR_UNREGISTER_TRACE(cpu_frequency);
161         GATOR_UNREGISTER_TRACE(cpu_idle);
162         pr_debug("gator: unregistered power event tracepoints\n");
164         for (i = 0; i < POWER_TOTAL; i++) {
165                 power_cpu_enabled[i] = 0;
166         }
169 void gator_trace_power_init(void)
171         int i;
172         for (i = 0; i < POWER_TOTAL; i++) {
173                 power_cpu_enabled[i] = 0;
174                 power_cpu_key[i] = gator_events_get_key();
175         }
177 #else
178 static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root)
180         return 0;
183 static void gator_trace_power_online(void)
187 static void gator_trace_power_offline(void)
191 static int gator_trace_power_start(void)
193         return 0;
196 static void gator_trace_power_stop(void)
200 void gator_trace_power_init(void)
203 #endif