aboutsummaryrefslogtreecommitdiffstats
path: root/include/os/linux/scale.c
diff options
context:
space:
mode:
Diffstat (limited to 'include/os/linux/scale.c')
-rw-r--r--include/os/linux/scale.c428
1 files changed, 0 insertions, 428 deletions
diff --git a/include/os/linux/scale.c b/include/os/linux/scale.c
deleted file mode 100644
index f8f0ef9..0000000
--- a/include/os/linux/scale.c
+++ /dev/null
@@ -1,428 +0,0 @@
1/*
2 * gk20a clock scaling profile
3 *
4 * Copyright (c) 2013-2023, NVIDIA Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/devfreq.h>
20#include <linux/export.h>
21#include <soc/tegra/chip-id.h>
22#include <linux/pm_qos.h>
23
24#include <governor.h>
25
26#include <nvgpu/kmem.h>
27#include <nvgpu/log.h>
28#include <nvgpu/gk20a.h>
29#include <nvgpu/clk_arb.h>
30
31#include "platform_gk20a.h"
32#include "scale.h"
33#include "os_linux.h"
34
35/*
36 * gk20a_scale_qos_notify()
37 *
38 * This function is called when the minimum QoS requirement for the device
39 * has changed. The function calls postscaling callback if it is defined.
40 */
41
42#if defined(CONFIG_GK20A_PM_QOS) && defined(CONFIG_COMMON_CLK)
43int gk20a_scale_qos_notify(struct notifier_block *nb,
44 unsigned long n, void *p)
45{
46 struct gk20a_scale_profile *profile =
47 container_of(nb, struct gk20a_scale_profile,
48 qos_notify_block);
49 struct gk20a *g = get_gk20a(profile->dev);
50 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
51 struct devfreq *devfreq = l->devfreq;
52
53 if (!devfreq)
54 return NOTIFY_OK;
55
56 mutex_lock(&devfreq->lock);
57 /* check for pm_qos min and max frequency requirement */
58 profile->qos_min_freq =
59 (unsigned long)pm_qos_read_min_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000UL;
60 profile->qos_max_freq =
61 (unsigned long)pm_qos_read_max_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000UL;
62
63 if (profile->qos_min_freq > profile->qos_max_freq) {
64 nvgpu_err(g,
65 "QoS: setting invalid limit, min_freq=%lu max_freq=%lu",
66 profile->qos_min_freq, profile->qos_max_freq);
67 profile->qos_min_freq = profile->qos_max_freq;
68 }
69
70 update_devfreq(devfreq);
71 mutex_unlock(&devfreq->lock);
72
73 return NOTIFY_OK;
74}
75#elif defined(CONFIG_GK20A_PM_QOS)
76int gk20a_scale_qos_notify(struct notifier_block *nb,
77 unsigned long n, void *p)
78{
79 struct gk20a_scale_profile *profile =
80 container_of(nb, struct gk20a_scale_profile,
81 qos_notify_block);
82 struct gk20a_platform *platform = dev_get_drvdata(profile->dev);
83 struct gk20a *g = get_gk20a(profile->dev);
84 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
85 unsigned long freq;
86
87 if (!platform->postscale)
88 return NOTIFY_OK;
89
90 /* get the frequency requirement. if devfreq is enabled, check if it
91 * has higher demand than qos */
92 freq = platform->clk_round_rate(profile->dev,
93 (u32)pm_qos_read_min_bound(PM_QOS_GPU_FREQ_BOUNDS));
94 if (l->devfreq)
95 freq = max(l->devfreq->previous_freq, freq);
96
97 /* Update gpu load because we may scale the emc target
98 * if the gpu load changed. */
99 nvgpu_pmu_load_update(g);
100 platform->postscale(profile->dev, freq);
101
102 return NOTIFY_OK;
103}
104#else
105int gk20a_scale_qos_notify(struct notifier_block *nb,
106 unsigned long n, void *p)
107{
108 return 0;
109}
110#endif
111
112/*
113 * gk20a_scale_make_freq_table(profile)
114 *
115 * This function initialises the frequency table for the given device profile
116 */
117
118static int gk20a_scale_make_freq_table(struct gk20a_scale_profile *profile)
119{
120 struct gk20a_platform *platform = dev_get_drvdata(profile->dev);
121 int num_freqs, err;
122 unsigned long *freqs;
123
124 if (platform->get_clk_freqs) {
125 /* get gpu frequency table */
126 err = platform->get_clk_freqs(profile->dev, &freqs,
127 &num_freqs);
128
129 if (err)
130 return -ENOSYS;
131 } else
132 return -ENOSYS;
133
134 profile->devfreq_profile.freq_table = (unsigned long *)freqs;
135 profile->devfreq_profile.max_state = num_freqs;
136
137 return 0;
138}
139
140/*
141 * gk20a_scale_target(dev, *freq, flags)
142 *
143 * This function scales the clock
144 */
145
146static int gk20a_scale_target(struct device *dev, unsigned long *freq,
147 u32 flags)
148{
149 struct gk20a_platform *platform = dev_get_drvdata(dev);
150 struct gk20a *g = platform->g;
151 struct gk20a_scale_profile *profile = g->scale_profile;
152 unsigned long local_freq = *freq;
153 unsigned long rounded_rate;
154#ifdef CONFIG_GK20A_PM_QOS
155 unsigned long min_freq = 0, max_freq = 0;
156#endif
157
158 if (nvgpu_clk_arb_has_active_req(g))
159 return 0;
160
161#ifdef CONFIG_GK20A_PM_QOS
162 /*
163 * devfreq takes care of min/max freq clipping in update_devfreq() then
164 * invoked devfreq->profile->target(), thus we only need to do freq
165 * clipping based on pm_qos constraint
166 */
167 min_freq = profile->qos_min_freq;
168 max_freq = profile->qos_max_freq;
169
170 if (min_freq > max_freq)
171 min_freq = max_freq;
172
173 /* Clip requested frequency */
174 if (local_freq < min_freq)
175 local_freq = min_freq;
176
177 if (local_freq > max_freq)
178 local_freq = max_freq;
179#endif
180
181 /* set the final frequency */
182 rounded_rate = platform->clk_round_rate(dev, local_freq);
183
184 /* Check for duplicate request */
185 if (rounded_rate == g->last_freq)
186 return 0;
187
188 if (g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_GPCCLK) == rounded_rate)
189 *freq = rounded_rate;
190 else {
191 g->ops.clk.set_rate(g, CTRL_CLK_DOMAIN_GPCCLK, rounded_rate);
192 *freq = g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_GPCCLK);
193 }
194
195 g->last_freq = *freq;
196
197 /* postscale will only scale emc (dram clock) if evaluating
198 * gk20a_tegra_get_emc_rate() produces a new or different emc
199 * target because the load or_and gpufreq has changed */
200 if (platform->postscale)
201 platform->postscale(dev, rounded_rate);
202
203 return 0;
204}
205
206/*
207 * update_load_estimate_busy_cycles(dev)
208 *
209 * Update load estimate using pmu idle counters. Result is normalised
210 * based on the time it was asked last time.
211 */
212
213static void update_load_estimate_busy_cycles(struct device *dev)
214{
215 struct gk20a *g = get_gk20a(dev);
216 struct gk20a_scale_profile *profile = g->scale_profile;
217 unsigned long dt;
218 u32 busy_cycles_norm;
219 ktime_t t;
220
221 t = ktime_get();
222 dt = ktime_us_delta(t, profile->last_event_time);
223
224 profile->dev_stat.total_time = dt;
225 profile->last_event_time = t;
226 nvgpu_pmu_busy_cycles_norm(g, &busy_cycles_norm);
227 profile->dev_stat.busy_time =
228 (busy_cycles_norm * dt) / PMU_BUSY_CYCLES_NORM_MAX;
229}
230
231/*
232 * gk20a_scale_suspend(dev)
233 *
234 * This function informs devfreq of suspend
235 */
236
237void gk20a_scale_suspend(struct device *dev)
238{
239 struct gk20a *g = get_gk20a(dev);
240 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
241 struct devfreq *devfreq = l->devfreq;
242
243 if (!devfreq)
244 return;
245
246 devfreq_suspend_device(devfreq);
247}
248
249/*
250 * gk20a_scale_resume(dev)
251 *
252 * This functions informs devfreq of resume
253 */
254
255void gk20a_scale_resume(struct device *dev)
256{
257 struct gk20a *g = get_gk20a(dev);
258 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
259 struct devfreq *devfreq = l->devfreq;
260
261 if (!devfreq)
262 return;
263
264 g->last_freq = 0;
265 devfreq_resume_device(devfreq);
266}
267
268/*
269 * gk20a_scale_get_dev_status(dev, *stat)
270 *
271 * This function queries the current device status.
272 */
273
274static int gk20a_scale_get_dev_status(struct device *dev,
275 struct devfreq_dev_status *stat)
276{
277 struct gk20a *g = get_gk20a(dev);
278 struct gk20a_scale_profile *profile = g->scale_profile;
279 struct gk20a_platform *platform = dev_get_drvdata(dev);
280
281 /* inform edp about new constraint */
282 if (platform->prescale)
283 platform->prescale(dev);
284
285 /* Make sure there are correct values for the current frequency */
286 profile->dev_stat.current_frequency =
287 g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_GPCCLK);
288
289 /* Update load estimate */
290 update_load_estimate_busy_cycles(dev);
291
292 /* Copy the contents of the current device status */
293 *stat = profile->dev_stat;
294
295 /* Finally, clear out the local values */
296 profile->dev_stat.total_time = 0;
297 profile->dev_stat.busy_time = 0;
298
299 return 0;
300}
301
302/*
303 * get_cur_freq(struct device *dev, unsigned long *freq)
304 *
305 * This function gets the current GPU clock rate.
306 */
307
308static int get_cur_freq(struct device *dev, unsigned long *freq)
309{
310 struct gk20a *g = get_gk20a(dev);
311 *freq = g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_GPCCLK);
312 return 0;
313}
314
315
316/*
317 * gk20a_scale_init(dev)
318 */
319
320void gk20a_scale_init(struct device *dev)
321{
322 struct gk20a_platform *platform = dev_get_drvdata(dev);
323 struct gk20a *g = platform->g;
324 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
325 struct gk20a_scale_profile *profile;
326 int err;
327
328 if (g->scale_profile)
329 return;
330
331 if (!platform->devfreq_governor && !platform->qos_notify)
332 return;
333
334 profile = nvgpu_kzalloc(g, sizeof(*profile));
335 if (!profile)
336 return;
337
338 profile->dev = dev;
339 profile->dev_stat.busy = false;
340
341 /* Create frequency table */
342 err = gk20a_scale_make_freq_table(profile);
343 if (err || !profile->devfreq_profile.max_state)
344 goto err_get_freqs;
345
346 profile->qos_min_freq = 0;
347 profile->qos_max_freq = UINT_MAX;
348
349 /* Store device profile so we can access it if devfreq governor
350 * init needs that */
351 g->scale_profile = profile;
352
353 if (platform->devfreq_governor) {
354 struct devfreq *devfreq;
355
356 profile->devfreq_profile.initial_freq =
357 profile->devfreq_profile.freq_table[0];
358 profile->devfreq_profile.target = gk20a_scale_target;
359 profile->devfreq_profile.get_dev_status =
360 gk20a_scale_get_dev_status;
361 profile->devfreq_profile.get_cur_freq = get_cur_freq;
362 profile->devfreq_profile.polling_ms = 25;
363
364 devfreq = devm_devfreq_add_device(dev,
365 &profile->devfreq_profile,
366 platform->devfreq_governor, NULL);
367
368 if (IS_ERR_OR_NULL(devfreq))
369 devfreq = NULL;
370
371 l->devfreq = devfreq;
372 }
373
374#ifdef CONFIG_GK20A_PM_QOS
375 /* Should we register QoS callback for this device? */
376 if (platform->qos_notify) {
377 profile->qos_notify_block.notifier_call =
378 platform->qos_notify;
379
380 pm_qos_add_min_notifier(PM_QOS_GPU_FREQ_BOUNDS,
381 &profile->qos_notify_block);
382 pm_qos_add_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
383 &profile->qos_notify_block);
384 }
385#endif
386
387 return;
388
389err_get_freqs:
390 nvgpu_kfree(g, profile);
391}
392
393void gk20a_scale_exit(struct device *dev)
394{
395 struct gk20a_platform *platform = dev_get_drvdata(dev);
396 struct gk20a *g = platform->g;
397
398#ifdef CONFIG_GK20A_PM_QOS
399 if (platform->qos_notify) {
400 pm_qos_remove_min_notifier(PM_QOS_GPU_FREQ_BOUNDS,
401 &g->scale_profile->qos_notify_block);
402 pm_qos_remove_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
403 &g->scale_profile->qos_notify_block);
404 }
405#endif
406
407 nvgpu_kfree(g, g->scale_profile);
408 g->scale_profile = NULL;
409}
410
411/*
412 * gk20a_scale_hw_init(dev)
413 *
414 * Initialize hardware portion of the device
415 */
416
417void gk20a_scale_hw_init(struct device *dev)
418{
419 struct gk20a_platform *platform = dev_get_drvdata(dev);
420 struct gk20a_scale_profile *profile = platform->g->scale_profile;
421
422 /* make sure that scaling has bee initialised */
423 if (!profile)
424 return;
425
426 profile->dev_stat.total_time = 0;
427 profile->last_event_time = ktime_get();
428}