MALI: utgard: upgrade DDK to r6p1-01rel0
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / common / mali_pm_metrics.c
1 /*
2  * Copyright (C) 2010-2014, 2016 ARM Limited. All rights reserved.
3  * 
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  * 
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10 #include "mali_pm_metrics.h"
11 #include "mali_osk_locks.h"
12 #include "mali_osk_mali.h"
13 #include <linux/ktime.h>
14
15 #define MALI_PM_TIME_SHIFT 0
16 #define MALI_UTILIZATION_MAX_PERIOD 80000000/* ns = 100ms */
17
18 _mali_osk_errcode_t mali_pm_metrics_init(struct mali_device *mdev)
19 {
20         int i = 0;
21
22         MALI_DEBUG_ASSERT(mdev != NULL);
23
24         mdev->mali_metrics.time_period_start = ktime_get();
25         mdev->mali_metrics.time_period_start_gp = mdev->mali_metrics.time_period_start;
26         mdev->mali_metrics.time_period_start_pp = mdev->mali_metrics.time_period_start;
27
28         mdev->mali_metrics.time_busy = 0;
29         mdev->mali_metrics.time_idle = 0;
30         mdev->mali_metrics.prev_busy = 0;
31         mdev->mali_metrics.prev_idle = 0;
32         mdev->mali_metrics.num_running_gp_cores = 0;
33         mdev->mali_metrics.num_running_pp_cores = 0;
34         mdev->mali_metrics.time_busy_gp = 0;
35         mdev->mali_metrics.time_idle_gp = 0;
36
37         for (i = 0; i < MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS; i++) {
38                 mdev->mali_metrics.time_busy_pp[i] = 0;
39                 mdev->mali_metrics.time_idle_pp[i] = 0;
40         }
41         mdev->mali_metrics.gpu_active = MALI_FALSE;
42
43         mdev->mali_metrics.lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_UNORDERED, _MALI_OSK_LOCK_ORDER_FIRST);
44         if (NULL == mdev->mali_metrics.lock) {
45                 return _MALI_OSK_ERR_NOMEM;
46         }
47
48         return _MALI_OSK_ERR_OK;
49 }
50
51 void mali_pm_metrics_term(struct mali_device *mdev)
52 {
53         _mali_osk_spinlock_irq_term(mdev->mali_metrics.lock);
54 }
55
56 /*caller needs to hold mdev->mali_metrics.lock before calling this function*/
57 void mali_pm_record_job_status(struct mali_device *mdev)
58 {
59         ktime_t now;
60         ktime_t diff;
61         u64 ns_time;
62
63         MALI_DEBUG_ASSERT(mdev != NULL);
64
65         now = ktime_get();
66         diff = ktime_sub(now, mdev->mali_metrics.time_period_start);
67
68         ns_time = (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
69         mdev->mali_metrics.time_busy += ns_time;
70         mdev->mali_metrics.time_period_start = now;
71 }
72
73 void mali_pm_record_gpu_idle(mali_bool is_gp)
74 {
75         ktime_t now;
76         ktime_t diff;
77         u64 ns_time;
78         struct mali_device *mdev = dev_get_drvdata(&mali_platform_device->dev);
79
80         MALI_DEBUG_ASSERT(mdev != NULL);
81
82         _mali_osk_spinlock_irq_lock(mdev->mali_metrics.lock);
83         now = ktime_get();
84
85         if (MALI_TRUE == is_gp) {
86                 --mdev->mali_metrics.num_running_gp_cores;
87                 if (0 == mdev->mali_metrics.num_running_gp_cores) {
88                         diff = ktime_sub(now, mdev->mali_metrics.time_period_start_gp);
89                         ns_time = (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
90                         mdev->mali_metrics.time_busy_gp += ns_time;
91                         mdev->mali_metrics.time_period_start_gp = now;
92
93                         if (0 == mdev->mali_metrics.num_running_pp_cores) {
94                                 MALI_DEBUG_ASSERT(mdev->mali_metrics.gpu_active == MALI_TRUE);
95                                 diff = ktime_sub(now, mdev->mali_metrics.time_period_start);
96                                 ns_time = (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
97                                 mdev->mali_metrics.time_busy += ns_time;
98                                 mdev->mali_metrics.time_period_start = now;
99                                 mdev->mali_metrics.gpu_active = MALI_FALSE;
100                         }
101                 }
102         } else {
103                 --mdev->mali_metrics.num_running_pp_cores;
104                 if (0 == mdev->mali_metrics.num_running_pp_cores) {
105                         diff = ktime_sub(now, mdev->mali_metrics.time_period_start_pp);
106                         ns_time = (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
107                         mdev->mali_metrics.time_busy_pp[0] += ns_time;
108                         mdev->mali_metrics.time_period_start_pp = now;
109
110                         if (0 == mdev->mali_metrics.num_running_gp_cores) {
111                                 MALI_DEBUG_ASSERT(mdev->mali_metrics.gpu_active == MALI_TRUE);
112                                 diff = ktime_sub(now, mdev->mali_metrics.time_period_start);
113                                 ns_time = (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
114                                 mdev->mali_metrics.time_busy += ns_time;
115                                 mdev->mali_metrics.time_period_start = now;
116                                 mdev->mali_metrics.gpu_active = MALI_FALSE;
117                         }
118                 }
119         }
120
121         _mali_osk_spinlock_irq_unlock(mdev->mali_metrics.lock);
122 }
123
124 void mali_pm_record_gpu_active(mali_bool is_gp)
125 {
126         ktime_t now;
127         ktime_t diff;
128         struct mali_device *mdev = dev_get_drvdata(&mali_platform_device->dev);
129
130         MALI_DEBUG_ASSERT(mdev != NULL);
131
132         _mali_osk_spinlock_irq_lock(mdev->mali_metrics.lock);
133         now = ktime_get();
134
135         if (MALI_TRUE == is_gp) {
136                 mdev->mali_metrics.num_running_gp_cores++;
137                 if (1 == mdev->mali_metrics.num_running_gp_cores) {
138                         diff = ktime_sub(now, mdev->mali_metrics.time_period_start_gp);
139                         mdev->mali_metrics.time_idle_gp += (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
140                         mdev->mali_metrics.time_period_start_gp = now;
141                         if (0 == mdev->mali_metrics.num_running_pp_cores) {
142                                 MALI_DEBUG_ASSERT(mdev->mali_metrics.gpu_active == MALI_FALSE);
143                                 diff = ktime_sub(now, mdev->mali_metrics.time_period_start);
144                                 mdev->mali_metrics.time_idle += (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
145                                 mdev->mali_metrics.time_period_start = now;
146                                 mdev->mali_metrics.gpu_active = MALI_TRUE;
147                         }
148                 } else {
149                         MALI_DEBUG_ASSERT(mdev->mali_metrics.gpu_active == MALI_TRUE);
150                 }
151         } else {
152                 mdev->mali_metrics.num_running_pp_cores++;
153                 if (1 == mdev->mali_metrics.num_running_pp_cores) {
154                         diff = ktime_sub(now, mdev->mali_metrics.time_period_start_pp);
155                         mdev->mali_metrics.time_idle_pp[0] += (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
156                         mdev->mali_metrics.time_period_start_pp = now;
157                         if (0 == mdev->mali_metrics.num_running_gp_cores) {
158                                 MALI_DEBUG_ASSERT(mdev->mali_metrics.gpu_active == MALI_FALSE);
159                                 diff = ktime_sub(now, mdev->mali_metrics.time_period_start);
160                                 mdev->mali_metrics.time_idle += (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
161                                 mdev->mali_metrics.time_period_start = now;
162                                 mdev->mali_metrics.gpu_active = MALI_TRUE;
163                         }
164                 } else {
165                         MALI_DEBUG_ASSERT(mdev->mali_metrics.gpu_active == MALI_TRUE);
166                 }
167         }
168
169         _mali_osk_spinlock_irq_unlock(mdev->mali_metrics.lock);
170 }
171
172
173 /*caller needs to hold mdev->mali_metrics.lock before calling this function*/
174 static void mali_pm_get_dvfs_utilisation_calc(struct mali_device *mdev, ktime_t now)
175 {
176         ktime_t diff;
177
178         MALI_DEBUG_ASSERT(mdev != NULL);
179
180         diff = ktime_sub(now, mdev->mali_metrics.time_period_start);
181
182         if (mdev->mali_metrics.gpu_active) {
183                 mdev->mali_metrics.time_busy += (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
184         } else {
185                 mdev->mali_metrics.time_idle += (u64)(ktime_to_ns(diff) >> MALI_PM_TIME_SHIFT);
186         }
187 }
188
189 /* Caller needs to hold mdev->mali_metrics.lock before calling this function. */
190 static void mali_pm_reset_dvfs_utilisation_unlocked(struct mali_device *mdev, ktime_t now)
191 {
192         /* Store previous value */
193         mdev->mali_metrics.prev_idle = mdev->mali_metrics.time_idle;
194         mdev->mali_metrics.prev_busy = mdev->mali_metrics.time_busy;
195
196         /* Reset current values */
197         mdev->mali_metrics.time_period_start = now;
198         mdev->mali_metrics.time_period_start_gp = now;
199         mdev->mali_metrics.time_period_start_pp = now;
200         mdev->mali_metrics.time_idle = 0;
201         mdev->mali_metrics.time_busy = 0;
202
203         mdev->mali_metrics.time_busy_gp = 0;
204         mdev->mali_metrics.time_idle_gp = 0;
205         mdev->mali_metrics.time_busy_pp[0] = 0;
206         mdev->mali_metrics.time_idle_pp[0] = 0;
207 }
208
209 void mali_pm_reset_dvfs_utilisation(struct mali_device *mdev)
210 {
211         _mali_osk_spinlock_irq_lock(mdev->mali_metrics.lock);
212         mali_pm_reset_dvfs_utilisation_unlocked(mdev, ktime_get());
213         _mali_osk_spinlock_irq_unlock(mdev->mali_metrics.lock);
214 }
215
216 void mali_pm_get_dvfs_utilisation(struct mali_device *mdev,
217                                   unsigned long *total_out, unsigned long *busy_out)
218 {
219         ktime_t now = ktime_get();
220         u64 busy = 0;
221         u64 total = 0;
222
223         _mali_osk_spinlock_irq_lock(mdev->mali_metrics.lock);
224
225         mali_pm_get_dvfs_utilisation_calc(mdev, now);
226
227         busy = mdev->mali_metrics.time_busy;
228         total = busy + mdev->mali_metrics.time_idle;
229
230         /* Reset stats if older than MALI_UTILIZATION_MAX_PERIOD (default
231          * 100ms) */
232         if (total >= MALI_UTILIZATION_MAX_PERIOD) {
233                 mali_pm_reset_dvfs_utilisation_unlocked(mdev, now);
234         } else if (total < (MALI_UTILIZATION_MAX_PERIOD / 2)) {
235                 total += mdev->mali_metrics.prev_idle +
236                          mdev->mali_metrics.prev_busy;
237                 busy += mdev->mali_metrics.prev_busy;
238         }
239
240         *total_out = (unsigned long)total;
241         *busy_out = (unsigned long)busy;
242         _mali_osk_spinlock_irq_unlock(mdev->mali_metrics.lock);
243 }
244
245 void mali_pm_metrics_spin_lock(void)
246 {
247         struct mali_device *mdev = dev_get_drvdata(&mali_platform_device->dev);
248         _mali_osk_spinlock_irq_lock(mdev->mali_metrics.lock);
249 }
250
251 void mali_pm_metrics_spin_unlock(void)
252 {
253         struct mali_device *mdev = dev_get_drvdata(&mali_platform_device->dev);
254         _mali_osk_spinlock_irq_unlock(mdev->mali_metrics.lock);
255 }