rk: ion: resolve build err
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / t6xx / kbase / src / common / mali_kbase_pm_metrics.c
1 /*
2  *
3  * (C) COPYRIGHT ARM Limited. All rights reserved.
4  *
5  * This program is free software and is provided to you under the terms of the
6  * GNU General Public License version 2 as published by the Free Software
7  * Foundation, and any use by you of this program is subject to the terms
8  * of such GNU licence.
9  *
10  * A copy of the licence is included with the program, and can also be obtained
11  * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
12  * Boston, MA  02110-1301, USA.
13  *
14  */
15
16
17
18
19
20 /**
21  * @file mali_kbase_pm_metrics.c
22  * Metrics for power management
23  */
24
25 #include <kbase/src/common/mali_kbase.h>
26 #include <kbase/src/common/mali_kbase_pm.h>
27
28 /* When VSync is being hit aim for utilisation between 70-90% */
29 #define KBASE_PM_VSYNC_MIN_UTILISATION          70
30 #define KBASE_PM_VSYNC_MAX_UTILISATION          90
31 /* Otherwise aim for 10-40% */
32 #define KBASE_PM_NO_VSYNC_MIN_UTILISATION       10
33 #define KBASE_PM_NO_VSYNC_MAX_UTILISATION       40
34
35 /* Shift used for kbasep_pm_metrics_data.time_busy/idle - units of (1 << 8) ns
36    This gives a maximum period between samples of 2^(32+8)/100 ns = slightly under 11s.
37    Exceeding this will cause overflow */
38 #define KBASE_PM_TIME_SHIFT                     8
39
40 static enum hrtimer_restart dvfs_callback(struct hrtimer *timer)
41 {
42         unsigned long flags;
43         kbase_pm_dvfs_action action;
44         kbasep_pm_metrics_data *metrics;
45
46         KBASE_DEBUG_ASSERT(timer != NULL);
47
48         metrics = container_of(timer, kbasep_pm_metrics_data, timer);
49         action = kbase_pm_get_dvfs_action(metrics->kbdev);
50
51         spin_lock_irqsave(&metrics->lock, flags);
52
53         if (metrics->timer_active)
54                 hrtimer_start(timer,
55                                           HR_TIMER_DELAY_MSEC(metrics->kbdev->pm.platform_dvfs_frequency),
56                                           HRTIMER_MODE_REL);
57
58         spin_unlock_irqrestore(&metrics->lock, flags);
59
60         return HRTIMER_NORESTART;
61 }
62
63 mali_error kbasep_pm_metrics_init(kbase_device *kbdev)
64 {
65         KBASE_DEBUG_ASSERT(kbdev != NULL);
66
67         kbdev->pm.metrics.kbdev = kbdev;
68         kbdev->pm.metrics.vsync_hit = 0;
69         kbdev->pm.metrics.utilisation = 0;
70
71         kbdev->pm.metrics.time_period_start = ktime_get();
72         kbdev->pm.metrics.time_busy = 0;
73         kbdev->pm.metrics.time_idle = 0;
74         kbdev->pm.metrics.gpu_active = MALI_TRUE;
75         kbdev->pm.metrics.timer_active = MALI_TRUE;
76
77         spin_lock_init(&kbdev->pm.metrics.lock);
78
79         hrtimer_init(&kbdev->pm.metrics.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
80         kbdev->pm.metrics.timer.function = dvfs_callback;
81
82         hrtimer_start(&kbdev->pm.metrics.timer, HR_TIMER_DELAY_MSEC(kbdev->pm.platform_dvfs_frequency), HRTIMER_MODE_REL);
83
84         kbase_pm_register_vsync_callback(kbdev);
85
86         return MALI_ERROR_NONE;
87 }
88
89 KBASE_EXPORT_TEST_API(kbasep_pm_metrics_init)
90
91 void kbasep_pm_metrics_term(kbase_device *kbdev)
92 {
93         unsigned long flags;
94         KBASE_DEBUG_ASSERT(kbdev != NULL);
95
96         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
97         kbdev->pm.metrics.timer_active = MALI_FALSE;
98         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
99
100         hrtimer_cancel(&kbdev->pm.metrics.timer);
101
102         kbase_pm_unregister_vsync_callback(kbdev);
103 }
104
105 KBASE_EXPORT_TEST_API(kbasep_pm_metrics_term)
106
107 void kbasep_pm_record_gpu_idle(kbase_device *kbdev)
108 {
109         unsigned long flags;
110         ktime_t now;
111         ktime_t diff;
112
113         KBASE_DEBUG_ASSERT(kbdev != NULL);
114
115         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
116
117         KBASE_DEBUG_ASSERT(kbdev->pm.metrics.gpu_active == MALI_TRUE);
118
119         kbdev->pm.metrics.gpu_active = MALI_FALSE;
120
121         now = ktime_get();
122         diff = ktime_sub(now, kbdev->pm.metrics.time_period_start);
123
124         kbdev->pm.metrics.time_busy += (u32) (ktime_to_ns(diff) >> KBASE_PM_TIME_SHIFT);
125         kbdev->pm.metrics.time_period_start = now;
126
127         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
128 }
129
130 KBASE_EXPORT_TEST_API(kbasep_pm_record_gpu_idle)
131
132 void kbasep_pm_record_gpu_active(kbase_device *kbdev)
133 {
134         unsigned long flags;
135         ktime_t now;
136         ktime_t diff;
137
138         KBASE_DEBUG_ASSERT(kbdev != NULL);
139
140         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
141
142         KBASE_DEBUG_ASSERT(kbdev->pm.metrics.gpu_active == MALI_FALSE);
143
144         kbdev->pm.metrics.gpu_active = MALI_TRUE;
145
146         now = ktime_get();
147         diff = ktime_sub(now, kbdev->pm.metrics.time_period_start);
148
149         kbdev->pm.metrics.time_idle += (u32) (ktime_to_ns(diff) >> KBASE_PM_TIME_SHIFT);
150         kbdev->pm.metrics.time_period_start = now;
151
152         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
153 }
154
155 KBASE_EXPORT_TEST_API(kbasep_pm_record_gpu_active)
156
157 void kbase_pm_report_vsync(kbase_device *kbdev, int buffer_updated)
158 {
159         unsigned long flags;
160         KBASE_DEBUG_ASSERT(kbdev != NULL);
161
162         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
163         kbdev->pm.metrics.vsync_hit = buffer_updated;
164         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
165 }
166
167 KBASE_EXPORT_TEST_API(kbase_pm_report_vsync)
168
169 /*caller needs to hold kbdev->pm.metrics.lock before calling this function*/
170 int kbase_pm_get_dvfs_utilisation(kbase_device *kbdev)
171 {
172         int utilisation = 0;
173         ktime_t now = ktime_get();
174         ktime_t diff;
175
176         KBASE_DEBUG_ASSERT(kbdev != NULL);
177
178         diff = ktime_sub(now, kbdev->pm.metrics.time_period_start);
179
180         if (kbdev->pm.metrics.gpu_active) {
181                 kbdev->pm.metrics.time_busy += (u32) (ktime_to_ns(diff) >> KBASE_PM_TIME_SHIFT);
182                 kbdev->pm.metrics.time_period_start = now;
183         } else {
184                 kbdev->pm.metrics.time_idle += (u32) (ktime_to_ns(diff) >> KBASE_PM_TIME_SHIFT);
185                 kbdev->pm.metrics.time_period_start = now;
186         }
187
188         if (kbdev->pm.metrics.time_idle + kbdev->pm.metrics.time_busy == 0) {
189                 /* No data - so we return NOP */
190                 utilisation = -1;
191                 goto out;
192         }
193
194         utilisation = (100 * kbdev->pm.metrics.time_busy) / (kbdev->pm.metrics.time_idle + kbdev->pm.metrics.time_busy);
195
196  out:
197
198         kbdev->pm.metrics.time_idle = 0;
199         kbdev->pm.metrics.time_busy = 0;
200
201         return utilisation;
202 }
203
204 kbase_pm_dvfs_action kbase_pm_get_dvfs_action(kbase_device *kbdev)
205 {
206         unsigned long flags;
207         int utilisation;
208         kbase_pm_dvfs_action action;
209
210         KBASE_DEBUG_ASSERT(kbdev != NULL);
211
212         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
213
214         utilisation = kbase_pm_get_dvfs_utilisation(kbdev);
215
216         if (utilisation < 0) {
217                 action = KBASE_PM_DVFS_NOP;
218                 utilisation = 0;
219                 goto out;
220         }
221
222         if (kbdev->pm.metrics.vsync_hit) {
223                 /* VSync is being met */
224                 if (utilisation < KBASE_PM_VSYNC_MIN_UTILISATION)
225                         action = KBASE_PM_DVFS_CLOCK_DOWN;
226                 else if (utilisation > KBASE_PM_VSYNC_MAX_UTILISATION)
227                         action = KBASE_PM_DVFS_CLOCK_UP;
228                 else
229                         action = KBASE_PM_DVFS_NOP;
230         } else {
231                 /* VSync is being missed */
232                 if (utilisation < KBASE_PM_NO_VSYNC_MIN_UTILISATION)
233                         action = KBASE_PM_DVFS_CLOCK_DOWN;
234                 else if (utilisation > KBASE_PM_NO_VSYNC_MAX_UTILISATION)
235                         action = KBASE_PM_DVFS_CLOCK_UP;
236                 else
237                         action = KBASE_PM_DVFS_NOP;
238         }
239
240         kbdev->pm.metrics.utilisation = utilisation;
241  out:
242 #ifdef CONFIG_MALI_T6XX_DVFS
243         kbase_platform_dvfs_event(kbdev, utilisation);
244 #endif                          /*CONFIG_MALI_T6XX_DVFS */
245         kbdev->pm.metrics.time_idle = 0;
246         kbdev->pm.metrics.time_busy = 0;
247         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
248
249         return action;
250 }
251 KBASE_EXPORT_TEST_API(kbase_pm_get_dvfs_action)
252
253 mali_bool kbase_pm_metrics_is_active(kbase_device *kbdev)
254 {
255         mali_bool isactive;
256         unsigned long flags;
257
258         KBASE_DEBUG_ASSERT(kbdev != NULL);
259
260         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
261         isactive = (kbdev->pm.metrics.timer_active == MALI_TRUE);
262         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
263
264         return isactive;
265 }
266 KBASE_EXPORT_TEST_API(kbase_pm_metrics_is_active)