xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/bifrost/ipa/mali_kbase_ipa_simple.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3  *
4  * (C) COPYRIGHT 2016-2018, 2020-2022 ARM Limited. All rights reserved.
5  *
6  * This program is free software and is provided to you under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation, and any use by you of this program is subject to the terms
9  * of such GNU license.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you can access it online at
18  * http://www.gnu.org/licenses/gpl-2.0.html.
19  *
20  */
21 
22 #include <linux/freezer.h>
23 #include <uapi/linux/thermal.h>
24 #include <linux/thermal.h>
25 #if IS_ENABLED(CONFIG_DEVFREQ_THERMAL)
26 #include <linux/devfreq_cooling.h>
27 #endif
28 #include <linux/of.h>
29 #include <linux/delay.h>
30 #include <linux/kthread.h>
31 
32 #include "mali_kbase.h"
33 #include "mali_kbase_defs.h"
34 #include "mali_kbase_ipa_simple.h"
35 #include "mali_kbase_ipa_debugfs.h"
36 
37 #if MALI_USE_CSF
38 
39 /* This is used if the dynamic power for top-level is estimated separately
40  * through the counter model. To roughly match the contribution of top-level
41  * power in the total dynamic power, when calculated through counter model,
42  * this scalar is used for the dynamic coefficient specified in the device tree
43  * for simple power model. This value was provided by the HW team after
44  * taking all the power data collected and dividing top level power by shader
45  * core power and then averaging it across all samples.
46  */
47 #define TOP_LEVEL_DYN_COEFF_SCALER (3)
48 
49 #endif /* MALI_USE_CSF */
50 
51 #if MALI_UNIT_TEST
52 
53 static int dummy_temp;
54 
kbase_simple_power_model_get_dummy_temp(struct thermal_zone_device * tz,int * temp)55 static int kbase_simple_power_model_get_dummy_temp(
56 	struct thermal_zone_device *tz,
57 	int *temp)
58 {
59 	*temp = READ_ONCE(dummy_temp);
60 	return 0;
61 }
62 
63 /* Intercept calls to the kernel function using a macro */
64 #ifdef thermal_zone_get_temp
65 #undef thermal_zone_get_temp
66 #endif
67 #define thermal_zone_get_temp(tz, temp) \
68 	kbase_simple_power_model_get_dummy_temp(tz, temp)
69 
kbase_simple_power_model_set_dummy_temp(int temp)70 void kbase_simple_power_model_set_dummy_temp(int temp)
71 {
72 	WRITE_ONCE(dummy_temp, temp);
73 }
74 KBASE_EXPORT_TEST_API(kbase_simple_power_model_set_dummy_temp);
75 
76 #endif /* MALI_UNIT_TEST */
77 
78 /*
79  * This model is primarily designed for the Juno platform. It may not be
80  * suitable for other platforms. The additional resources in this model
81  * should preferably be minimal, as this model is rarely used when a dynamic
82  * model is available.
83  */
84 
85 /**
86  * struct kbase_ipa_model_simple_data - IPA context per device
87  * @dynamic_coefficient: dynamic coefficient of the model
88  * @static_coefficient:  static coefficient of the model
89  * @ts:                  Thermal scaling coefficients of the model
90  * @tz_name:             Thermal zone name
91  * @gpu_tz:              thermal zone device
92  * @poll_temperature_thread: Handle for temperature polling thread
93  * @current_temperature: Most recent value of polled temperature
94  * @temperature_poll_interval_ms: How often temperature should be checked, in ms
95  */
96 
97 struct kbase_ipa_model_simple_data {
98 	u32 dynamic_coefficient;
99 	u32 static_coefficient;
100 	s32 ts[4];
101 	char tz_name[THERMAL_NAME_LENGTH];
102 	struct thermal_zone_device *gpu_tz;
103 	struct task_struct *poll_temperature_thread;
104 	int current_temperature;
105 	int temperature_poll_interval_ms;
106 };
107 #define FALLBACK_STATIC_TEMPERATURE 55000
108 
109 /**
110  * calculate_temp_scaling_factor() - Calculate temperature scaling coefficient
111  * @ts:		Signed coefficients, in order t^0 to t^3, with units Deg^-N
112  * @t:		Temperature, in mDeg C. Range: -2^17 < t < 2^17
113  *
114  * Scale the temperature according to a cubic polynomial whose coefficients are
115  * provided in the device tree. The result is used to scale the static power
116  * coefficient, where 1000000 means no change.
117  *
118  * Return: Temperature scaling factor. Range 0 <= ret <= 10,000,000.
119  */
calculate_temp_scaling_factor(s32 ts[4],s64 t)120 static u32 calculate_temp_scaling_factor(s32 ts[4], s64 t)
121 {
122 	/* Range: -2^24 < t2 < 2^24 m(Deg^2) */
123 	const s64 t2 = div_s64((t * t), 1000);
124 
125 	/* Range: -2^31 < t3 < 2^31 m(Deg^3) */
126 	const s64 t3 = div_s64((t * t2), 1000);
127 
128 	/*
129 	 * Sum the parts. t^[1-3] are in m(Deg^N), but the coefficients are in
130 	 * Deg^-N, so we need to multiply the last coefficient by 1000.
131 	 * Range: -2^63 < res_big < 2^63
132 	 */
133 	const s64 res_big = ts[3] * t3    /* +/- 2^62 */
134 			  + ts[2] * t2    /* +/- 2^55 */
135 			  + ts[1] * t     /* +/- 2^48 */
136 			  + ts[0] * (s64)1000; /* +/- 2^41 */
137 
138 	/* Range: -2^60 < res_unclamped < 2^60 */
139 	s64 res_unclamped = div_s64(res_big, 1000);
140 
141 	/* Clamp to range of 0x to 10x the static power */
142 	return clamp(res_unclamped, (s64) 0, (s64) 10000000);
143 }
144 
145 /* We can't call thermal_zone_get_temp() directly in model_static_coeff(),
146  * because we don't know if tz->lock is held in the same thread. So poll it in
147  * a separate thread to get around this.
148  */
poll_temperature(void * data)149 static int poll_temperature(void *data)
150 {
151 	struct kbase_ipa_model_simple_data *model_data =
152 			(struct kbase_ipa_model_simple_data *) data;
153 	int temp;
154 
155 	set_freezable();
156 
157 	while (!kthread_should_stop()) {
158 		struct thermal_zone_device *tz = READ_ONCE(model_data->gpu_tz);
159 
160 		if (tz) {
161 			int ret;
162 
163 			ret = thermal_zone_get_temp(tz, &temp);
164 			if (ret) {
165 				pr_warn_ratelimited("Error reading temperature for gpu thermal zone: %d\n",
166 						    ret);
167 				temp = FALLBACK_STATIC_TEMPERATURE;
168 			}
169 		} else {
170 			temp = FALLBACK_STATIC_TEMPERATURE;
171 		}
172 
173 		WRITE_ONCE(model_data->current_temperature, temp);
174 
175 		msleep_interruptible(READ_ONCE(model_data->temperature_poll_interval_ms));
176 
177 		try_to_freeze();
178 	}
179 
180 	return 0;
181 }
182 
model_static_coeff(struct kbase_ipa_model * model,u32 * coeffp)183 static int model_static_coeff(struct kbase_ipa_model *model, u32 *coeffp)
184 {
185 	u32 temp_scaling_factor;
186 	struct kbase_ipa_model_simple_data *model_data =
187 		(struct kbase_ipa_model_simple_data *) model->model_data;
188 	u64 coeff_big;
189 	int temp;
190 
191 	temp = READ_ONCE(model_data->current_temperature);
192 
193 	/* Range: 0 <= temp_scaling_factor < 2^24 */
194 	temp_scaling_factor = calculate_temp_scaling_factor(model_data->ts,
195 							    temp);
196 
197 	/*
198 	 * Range: 0 <= coeff_big < 2^52 to avoid overflowing *coeffp. This
199 	 * means static_coefficient must be in range
200 	 * 0 <= static_coefficient < 2^28.
201 	 */
202 	coeff_big = (u64) model_data->static_coefficient * (u64) temp_scaling_factor;
203 	*coeffp = div_u64(coeff_big, 1000000);
204 
205 	return 0;
206 }
207 
model_dynamic_coeff(struct kbase_ipa_model * model,u32 * coeffp)208 static int model_dynamic_coeff(struct kbase_ipa_model *model, u32 *coeffp)
209 {
210 	struct kbase_ipa_model_simple_data *model_data =
211 		(struct kbase_ipa_model_simple_data *) model->model_data;
212 
213 #if MALI_USE_CSF
214 	/* On CSF GPUs, the dynamic power for top-level and shader cores is
215 	 * estimated separately. Currently there is a single dynamic
216 	 * coefficient value provided in the device tree for simple model.
217 	 * As per the discussion with HW team the coefficient value needs to
218 	 * be scaled down for top-level to limit its contribution in the
219 	 * total dyanmic power.
220 	 */
221 	coeffp[KBASE_IPA_BLOCK_TYPE_TOP_LEVEL] =
222 		model_data->dynamic_coefficient / TOP_LEVEL_DYN_COEFF_SCALER;
223 	coeffp[KBASE_IPA_BLOCK_TYPE_SHADER_CORES] =
224 		model_data->dynamic_coefficient;
225 #else
226 	*coeffp = model_data->dynamic_coefficient;
227 #endif
228 
229 	return 0;
230 }
231 
add_params(struct kbase_ipa_model * model)232 static int add_params(struct kbase_ipa_model *model)
233 {
234 	int err = 0;
235 	struct kbase_ipa_model_simple_data *model_data =
236 			(struct kbase_ipa_model_simple_data *)model->model_data;
237 
238 	err = kbase_ipa_model_add_param_s32(model, "static-coefficient",
239 					    (s32 *)&model_data->static_coefficient, 1, true);
240 	if (err)
241 		goto end;
242 
243 	err = kbase_ipa_model_add_param_s32(model, "dynamic-coefficient",
244 					    (s32 *)&model_data->dynamic_coefficient, 1, true);
245 	if (err)
246 		goto end;
247 
248 	err = kbase_ipa_model_add_param_s32(model, "ts",
249 					    model_data->ts, 4, true);
250 	if (err)
251 		goto end;
252 
253 	err = kbase_ipa_model_add_param_string(model, "thermal-zone",
254 					       model_data->tz_name,
255 					       sizeof(model_data->tz_name), true);
256 	if (err)
257 		goto end;
258 
259 	model_data->temperature_poll_interval_ms = 200;
260 	err = kbase_ipa_model_add_param_s32(model, "temp-poll-interval-ms",
261 					    &model_data->temperature_poll_interval_ms,
262 					    1, false);
263 
264 end:
265 	return err;
266 }
267 
kbase_simple_power_model_init(struct kbase_ipa_model * model)268 static int kbase_simple_power_model_init(struct kbase_ipa_model *model)
269 {
270 	int err;
271 	struct kbase_ipa_model_simple_data *model_data;
272 
273 	model_data = kzalloc(sizeof(struct kbase_ipa_model_simple_data),
274 			     GFP_KERNEL);
275 	if (!model_data)
276 		return -ENOMEM;
277 
278 	model->model_data = (void *) model_data;
279 
280 	model_data->current_temperature = FALLBACK_STATIC_TEMPERATURE;
281 	model_data->poll_temperature_thread = kthread_run(poll_temperature,
282 							  (void *) model_data,
283 							  "mali-simple-power-model-temp-poll");
284 	if (IS_ERR(model_data->poll_temperature_thread)) {
285 		err = PTR_ERR(model_data->poll_temperature_thread);
286 		kfree(model_data);
287 		return err;
288 	}
289 
290 	err = add_params(model);
291 	if (err) {
292 		kbase_ipa_model_param_free_all(model);
293 		kthread_stop(model_data->poll_temperature_thread);
294 		kfree(model_data);
295 	}
296 
297 	return err;
298 }
299 
kbase_simple_power_model_recalculate(struct kbase_ipa_model * model)300 static int kbase_simple_power_model_recalculate(struct kbase_ipa_model *model)
301 {
302 	struct kbase_ipa_model_simple_data *model_data =
303 			(struct kbase_ipa_model_simple_data *)model->model_data;
304 	struct thermal_zone_device *tz;
305 
306 	lockdep_assert_held(&model->kbdev->ipa.lock);
307 
308 	if (!strnlen(model_data->tz_name, sizeof(model_data->tz_name))) {
309 		model_data->gpu_tz = NULL;
310 	} else {
311 		char tz_name[THERMAL_NAME_LENGTH];
312 		u32 string_len = strscpy(tz_name, model_data->tz_name, sizeof(tz_name));
313 
314 		string_len += sizeof(char);
315 		/* Make sure that the source string fit into the buffer. */
316 		KBASE_DEBUG_ASSERT(string_len <= sizeof(tz_name));
317 		CSTD_UNUSED(string_len);
318 
319 		/* Release ipa.lock so that thermal_list_lock is not acquired
320 		 * with ipa.lock held, thereby avoid lock ordering violation
321 		 * lockdep warning. The warning comes as a chain of locks
322 		 * ipa.lock --> thermal_list_lock --> tz->lock gets formed
323 		 * on registering devfreq cooling device when probe method
324 		 * of mali platform driver is invoked.
325 		 */
326 		mutex_unlock(&model->kbdev->ipa.lock);
327 		tz = thermal_zone_get_zone_by_name(tz_name);
328 		mutex_lock(&model->kbdev->ipa.lock);
329 
330 		if (IS_ERR_OR_NULL(tz)) {
331 			pr_warn_ratelimited(
332 				"Error %d getting thermal zone \'%s\', not yet ready?\n",
333 				PTR_ERR_OR_ZERO(tz), tz_name);
334 			return -EPROBE_DEFER;
335 		}
336 
337 		/* Check if another thread raced against us & updated the
338 		 * thermal zone name string. Update the gpu_tz pointer only if
339 		 * the name string did not change whilst we retrieved the new
340 		 * thermal_zone_device pointer, otherwise model_data->tz_name &
341 		 * model_data->gpu_tz would become inconsistent with each other.
342 		 * The below check will succeed only for the thread which last
343 		 * updated the name string.
344 		 */
345 		if (strncmp(tz_name, model_data->tz_name, sizeof(tz_name)) == 0)
346 			model_data->gpu_tz = tz;
347 	}
348 
349 	return 0;
350 }
351 
kbase_simple_power_model_term(struct kbase_ipa_model * model)352 static void kbase_simple_power_model_term(struct kbase_ipa_model *model)
353 {
354 	struct kbase_ipa_model_simple_data *model_data =
355 			(struct kbase_ipa_model_simple_data *)model->model_data;
356 
357 	kthread_stop(model_data->poll_temperature_thread);
358 
359 	kfree(model_data);
360 }
361 
362 struct kbase_ipa_model_ops kbase_simple_ipa_model_ops = {
363 		.name = "mali-simple-power-model",
364 		.init = &kbase_simple_power_model_init,
365 		.recalculate = &kbase_simple_power_model_recalculate,
366 		.term = &kbase_simple_power_model_term,
367 		.get_dynamic_coeff = &model_dynamic_coeff,
368 		.get_static_coeff = &model_static_coeff,
369 };
370 KBASE_EXPORT_TEST_API(kbase_simple_ipa_model_ops);
371