summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/gk20a_scale.c
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2017-10-30 15:52:52 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-11-01 13:55:41 -0400
commit15e259bc5255e891f776a84b5f28a97ea0567178 (patch)
treeca4a92cafe8e01b8bdb87c0bbdc5fc18913af841 /drivers/gpu/nvgpu/gk20a/gk20a_scale.c
parent964a849d6176da362c375d7d72b94289e9b905de (diff)
gpu: nvgpu: Move gk20a_scale to be Linux only
Move gk20a_scale.[ch] to be common/linux/scale.[ch]. The code is Linux specific, and only referred from Linux specific source files. Change the license back to GPL. JIRA NVGPU-259 Change-Id: I89fa905a1fea4f93c826ddfe2ffce34aefc1b0a2 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1588650 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/gk20a_scale.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a_scale.c434
1 files changed, 0 insertions, 434 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_scale.c b/drivers/gpu/nvgpu/gk20a/gk20a_scale.c
deleted file mode 100644
index ae426eec..00000000
--- a/drivers/gpu/nvgpu/gk20a/gk20a_scale.c
+++ /dev/null
@@ -1,434 +0,0 @@
1/*
2 * gk20a clock scaling profile
3 *
4 * Copyright (c) 2013-2017, NVIDIA Corporation. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25#include <linux/devfreq.h>
26#include <linux/export.h>
27#include <soc/tegra/chip-id.h>
28#include <linux/pm_qos.h>
29
30#include <governor.h>
31
32#include <nvgpu/kmem.h>
33#include <nvgpu/log.h>
34
35#include "gk20a.h"
36#include "platform_gk20a.h"
37#include "gk20a_scale.h"
38#include "common/linux/os_linux.h"
39
40/*
41 * gk20a_scale_qos_notify()
42 *
43 * This function is called when the minimum QoS requirement for the device
44 * has changed. The function calls postscaling callback if it is defined.
45 */
46
47#if defined(CONFIG_COMMON_CLK)
48int gk20a_scale_qos_notify(struct notifier_block *nb,
49 unsigned long n, void *p)
50{
51 struct gk20a_scale_profile *profile =
52 container_of(nb, struct gk20a_scale_profile,
53 qos_notify_block);
54 struct gk20a *g = get_gk20a(profile->dev);
55 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
56 struct devfreq *devfreq = l->devfreq;
57
58 if (!devfreq)
59 return NOTIFY_OK;
60
61 mutex_lock(&devfreq->lock);
62 /* check for pm_qos min and max frequency requirement */
63 profile->qos_min_freq =
64 (unsigned long)pm_qos_read_min_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000UL;
65 profile->qos_max_freq =
66 (unsigned long)pm_qos_read_max_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000UL;
67
68 if (profile->qos_min_freq > profile->qos_max_freq) {
69 nvgpu_err(g,
70 "QoS: setting invalid limit, min_freq=%lu max_freq=%lu",
71 profile->qos_min_freq, profile->qos_max_freq);
72 profile->qos_min_freq = profile->qos_max_freq;
73 }
74
75 update_devfreq(devfreq);
76 mutex_unlock(&devfreq->lock);
77
78 return NOTIFY_OK;
79}
80#else
81int gk20a_scale_qos_notify(struct notifier_block *nb,
82 unsigned long n, void *p)
83{
84 struct gk20a_scale_profile *profile =
85 container_of(nb, struct gk20a_scale_profile,
86 qos_notify_block);
87 struct gk20a_platform *platform = dev_get_drvdata(profile->dev);
88 struct gk20a *g = get_gk20a(profile->dev);
89 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
90 unsigned long freq;
91
92 if (!platform->postscale)
93 return NOTIFY_OK;
94
95 /* get the frequency requirement. if devfreq is enabled, check if it
96 * has higher demand than qos */
97 freq = platform->clk_round_rate(profile->dev,
98 (u32)pm_qos_read_min_bound(PM_QOS_GPU_FREQ_BOUNDS));
99 if (l->devfreq)
100 freq = max(l->devfreq->previous_freq, freq);
101
102 /* Update gpu load because we may scale the emc target
103 * if the gpu load changed. */
104 nvgpu_pmu_load_update(g);
105 platform->postscale(profile->dev, freq);
106
107 return NOTIFY_OK;
108}
109#endif
110
111/*
112 * gk20a_scale_make_freq_table(profile)
113 *
114 * This function initialises the frequency table for the given device profile
115 */
116
117static int gk20a_scale_make_freq_table(struct gk20a_scale_profile *profile)
118{
119 struct gk20a_platform *platform = dev_get_drvdata(profile->dev);
120 int num_freqs, err;
121 unsigned long *freqs;
122
123 if (platform->get_clk_freqs) {
124 /* get gpu frequency table */
125 err = platform->get_clk_freqs(profile->dev, &freqs,
126 &num_freqs);
127 if (err)
128 return -ENOSYS;
129 } else
130 return -ENOSYS;
131
132 profile->devfreq_profile.freq_table = (unsigned long *)freqs;
133 profile->devfreq_profile.max_state = num_freqs;
134
135 return 0;
136}
137
138/*
139 * gk20a_scale_target(dev, *freq, flags)
140 *
141 * This function scales the clock
142 */
143
144static int gk20a_scale_target(struct device *dev, unsigned long *freq,
145 u32 flags)
146{
147 struct gk20a_platform *platform = dev_get_drvdata(dev);
148 struct gk20a *g = platform->g;
149 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
150 struct gk20a_scale_profile *profile = g->scale_profile;
151 struct devfreq *devfreq = l->devfreq;
152 unsigned long local_freq = *freq;
153 unsigned long rounded_rate;
154 unsigned long min_freq = 0, max_freq = 0;
155
156 /*
157 * Calculate floor and cap frequency values
158 *
159 * Policy :
160 * We have two APIs to clip the frequency
161 * 1. devfreq
162 * 2. pm_qos
163 *
164 * To calculate floor (min) freq, we select MAX of floor frequencies
165 * requested from both APIs
166 * To get cap (max) freq, we select MIN of max frequencies
167 *
168 * In case we have conflict (min_freq > max_freq) after above
169 * steps, we ensure that max_freq wins over min_freq
170 */
171 min_freq = max_t(u32, devfreq->min_freq, profile->qos_min_freq);
172 max_freq = min_t(u32, devfreq->max_freq, profile->qos_max_freq);
173
174 if (min_freq > max_freq)
175 min_freq = max_freq;
176
177 /* Clip requested frequency */
178 if (local_freq < min_freq)
179 local_freq = min_freq;
180
181 if (local_freq > max_freq)
182 local_freq = max_freq;
183
184 /* set the final frequency */
185 rounded_rate = platform->clk_round_rate(dev, local_freq);
186
187 /* Check for duplicate request */
188 if (rounded_rate == g->last_freq)
189 return 0;
190
191 if (g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_GPCCLK) == rounded_rate)
192 *freq = rounded_rate;
193 else {
194 g->ops.clk.set_rate(g, CTRL_CLK_DOMAIN_GPCCLK, rounded_rate);
195 *freq = g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_GPCCLK);
196 }
197
198 g->last_freq = *freq;
199
200 /* postscale will only scale emc (dram clock) if evaluating
201 * gk20a_tegra_get_emc_rate() produces a new or different emc
202 * target because the load or_and gpufreq has changed */
203 if (platform->postscale)
204 platform->postscale(dev, rounded_rate);
205
206 return 0;
207}
208
209/*
210 * update_load_estimate_gpmu(profile)
211 *
212 * Update load estimate using gpmu. The gpmu value is normalised
213 * based on the time it was asked last time.
214 */
215
216static void update_load_estimate_gpmu(struct device *dev)
217{
218 struct gk20a *g = get_gk20a(dev);
219 struct gk20a_scale_profile *profile = g->scale_profile;
220 unsigned long dt;
221 u32 busy_time;
222 ktime_t t;
223
224 t = ktime_get();
225 dt = ktime_us_delta(t, profile->last_event_time);
226
227 profile->dev_stat.total_time = dt;
228 profile->last_event_time = t;
229 nvgpu_pmu_load_norm(g, &busy_time);
230 profile->dev_stat.busy_time = (busy_time * dt) / 1000;
231}
232
233/*
234 * gk20a_scale_suspend(dev)
235 *
236 * This function informs devfreq of suspend
237 */
238
239void gk20a_scale_suspend(struct device *dev)
240{
241 struct gk20a *g = get_gk20a(dev);
242 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
243 struct devfreq *devfreq = l->devfreq;
244
245 if (!devfreq)
246 return;
247
248 devfreq_suspend_device(devfreq);
249}
250
251/*
252 * gk20a_scale_resume(dev)
253 *
254 * This functions informs devfreq of resume
255 */
256
257void gk20a_scale_resume(struct device *dev)
258{
259 struct gk20a *g = get_gk20a(dev);
260 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
261 struct devfreq *devfreq = l->devfreq;
262
263 if (!devfreq)
264 return;
265
266 g->last_freq = 0;
267 devfreq_resume_device(devfreq);
268}
269
270/*
271 * gk20a_scale_get_dev_status(dev, *stat)
272 *
273 * This function queries the current device status.
274 */
275
276static int gk20a_scale_get_dev_status(struct device *dev,
277 struct devfreq_dev_status *stat)
278{
279 struct gk20a *g = get_gk20a(dev);
280 struct gk20a_scale_profile *profile = g->scale_profile;
281 struct gk20a_platform *platform = dev_get_drvdata(dev);
282
283 /* update the software shadow */
284 nvgpu_pmu_load_update(g);
285
286 /* inform edp about new constraint */
287 if (platform->prescale)
288 platform->prescale(dev);
289
290 /* Make sure there are correct values for the current frequency */
291 profile->dev_stat.current_frequency =
292 g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_GPCCLK);
293
294 /* Update load estimate */
295 update_load_estimate_gpmu(dev);
296
297 /* Copy the contents of the current device status */
298 *stat = profile->dev_stat;
299
300 /* Finally, clear out the local values */
301 profile->dev_stat.total_time = 0;
302 profile->dev_stat.busy_time = 0;
303
304 return 0;
305}
306
307/*
308 * get_cur_freq(struct device *dev, unsigned long *freq)
309 *
310 * This function gets the current GPU clock rate.
311 */
312
313static int get_cur_freq(struct device *dev, unsigned long *freq)
314{
315 struct gk20a *g = get_gk20a(dev);
316 *freq = g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_GPCCLK);
317 return 0;
318}
319
320
321/*
322 * gk20a_scale_init(dev)
323 */
324
325void gk20a_scale_init(struct device *dev)
326{
327 struct gk20a_platform *platform = dev_get_drvdata(dev);
328 struct gk20a *g = platform->g;
329 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
330 struct gk20a_scale_profile *profile;
331 int err;
332
333 if (g->scale_profile)
334 return;
335
336 if (!platform->devfreq_governor && !platform->qos_notify)
337 return;
338
339 profile = nvgpu_kzalloc(g, sizeof(*profile));
340
341 profile->dev = dev;
342 profile->dev_stat.busy = false;
343
344 /* Create frequency table */
345 err = gk20a_scale_make_freq_table(profile);
346 if (err || !profile->devfreq_profile.max_state)
347 goto err_get_freqs;
348
349 profile->qos_min_freq = 0;
350 profile->qos_max_freq = UINT_MAX;
351
352 /* Store device profile so we can access it if devfreq governor
353 * init needs that */
354 g->scale_profile = profile;
355
356 if (platform->devfreq_governor) {
357 struct devfreq *devfreq;
358
359 profile->devfreq_profile.initial_freq =
360 profile->devfreq_profile.freq_table[0];
361 profile->devfreq_profile.target = gk20a_scale_target;
362 profile->devfreq_profile.get_dev_status =
363 gk20a_scale_get_dev_status;
364 profile->devfreq_profile.get_cur_freq = get_cur_freq;
365 profile->devfreq_profile.polling_ms = 25;
366
367 devfreq = devfreq_add_device(dev,
368 &profile->devfreq_profile,
369 platform->devfreq_governor, NULL);
370
371 if (IS_ERR(devfreq))
372 devfreq = NULL;
373
374 l->devfreq = devfreq;
375 }
376
377 /* Should we register QoS callback for this device? */
378 if (platform->qos_notify) {
379 profile->qos_notify_block.notifier_call =
380 platform->qos_notify;
381
382 pm_qos_add_min_notifier(PM_QOS_GPU_FREQ_BOUNDS,
383 &profile->qos_notify_block);
384 pm_qos_add_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
385 &profile->qos_notify_block);
386 }
387
388 return;
389
390err_get_freqs:
391 nvgpu_kfree(g, profile);
392}
393
394void gk20a_scale_exit(struct device *dev)
395{
396 struct gk20a_platform *platform = dev_get_drvdata(dev);
397 struct gk20a *g = platform->g;
398 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
399 int err;
400
401 if (platform->qos_notify) {
402 pm_qos_remove_min_notifier(PM_QOS_GPU_FREQ_BOUNDS,
403 &g->scale_profile->qos_notify_block);
404 pm_qos_remove_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
405 &g->scale_profile->qos_notify_block);
406 }
407
408 if (platform->devfreq_governor) {
409 err = devfreq_remove_device(l->devfreq);
410 l->devfreq = NULL;
411 }
412
413 nvgpu_kfree(g, g->scale_profile);
414 g->scale_profile = NULL;
415}
416
417/*
418 * gk20a_scale_hw_init(dev)
419 *
420 * Initialize hardware portion of the device
421 */
422
423void gk20a_scale_hw_init(struct device *dev)
424{
425 struct gk20a_platform *platform = dev_get_drvdata(dev);
426 struct gk20a_scale_profile *profile = platform->g->scale_profile;
427
428 /* make sure that scaling has bee initialised */
429 if (!profile)
430 return;
431
432 profile->dev_stat.total_time = 0;
433 profile->last_event_time = ktime_get();
434}