xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/mali400/mali/common/mali_pm_metrics.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2010-2014, 2016-2017 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 
mali_pm_metrics_init(struct mali_device * mdev)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 
mali_pm_metrics_term(struct mali_device * mdev)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*/
mali_pm_record_job_status(struct mali_device * mdev)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 
mali_pm_record_gpu_idle(mali_bool is_gp)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 
mali_pm_record_gpu_active(mali_bool is_gp)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*/
mali_pm_get_dvfs_utilisation_calc(struct mali_device * mdev,ktime_t now)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. */
mali_pm_reset_dvfs_utilisation_unlocked(struct mali_device * mdev,ktime_t now)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 
mali_pm_reset_dvfs_utilisation(struct mali_device * mdev)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 
mali_pm_get_dvfs_utilisation(struct mali_device * mdev,unsigned long * total_out,unsigned long * busy_out)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 
mali_pm_metrics_spin_lock(void)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 
mali_pm_metrics_spin_unlock(void)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 }
256