diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 2 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a_scale.c | 77 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a_scale.h | 2 |
3 files changed, 60 insertions, 21 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 07752d66..ffddebe7 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h | |||
@@ -936,8 +936,6 @@ struct gk20a { | |||
936 | wait_queue_head_t sw_irq_nonstall_last_handled_wq; | 936 | wait_queue_head_t sw_irq_nonstall_last_handled_wq; |
937 | 937 | ||
938 | struct devfreq *devfreq; | 938 | struct devfreq *devfreq; |
939 | u32 devfreq_max_freq; | ||
940 | u32 devfreq_min_freq; | ||
941 | 939 | ||
942 | struct gk20a_scale_profile *scale_profile; | 940 | struct gk20a_scale_profile *scale_profile; |
943 | 941 | ||
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_scale.c b/drivers/gpu/nvgpu/gk20a/gk20a_scale.c index ac28d967..d2229a6a 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a_scale.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a_scale.c | |||
@@ -50,28 +50,25 @@ int gk20a_scale_qos_notify(struct notifier_block *nb, | |||
50 | qos_notify_block); | 50 | qos_notify_block); |
51 | struct gk20a *g = get_gk20a(profile->dev); | 51 | struct gk20a *g = get_gk20a(profile->dev); |
52 | struct devfreq *devfreq = g->devfreq; | 52 | struct devfreq *devfreq = g->devfreq; |
53 | s32 min_qos_freq, max_qos_freq; | ||
54 | 53 | ||
55 | if (!devfreq) | 54 | if (!devfreq) |
56 | return NOTIFY_OK; | 55 | return NOTIFY_OK; |
57 | 56 | ||
58 | /* check for pm_qos min and max frequency requirement */ | ||
59 | min_qos_freq = pm_qos_read_min_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000; | ||
60 | max_qos_freq = pm_qos_read_max_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000; | ||
61 | |||
62 | mutex_lock(&devfreq->lock); | 57 | mutex_lock(&devfreq->lock); |
58 | /* check for pm_qos min and max frequency requirement */ | ||
59 | profile->qos_min_freq = | ||
60 | pm_qos_read_min_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000; | ||
61 | profile->qos_max_freq = | ||
62 | pm_qos_read_max_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000; | ||
63 | |||
64 | if (profile->qos_min_freq > profile->qos_max_freq) { | ||
65 | gk20a_err(g->dev, | ||
66 | "QoS: setting invalid limit, min_freq=%lu max_freq=%lu\n", | ||
67 | profile->qos_min_freq, profile->qos_max_freq); | ||
68 | profile->qos_min_freq = profile->qos_max_freq; | ||
69 | } | ||
63 | 70 | ||
64 | devfreq->min_freq = max_t(u32, g->devfreq_min_freq, min_qos_freq); | ||
65 | devfreq->max_freq = min_t(u32, g->devfreq_max_freq, max_qos_freq); | ||
66 | |||
67 | WARN_ON(devfreq->min_freq > devfreq->max_freq); | ||
68 | |||
69 | /* | ||
70 | * update_devfreq() will adjust the current (or newly estimated) | ||
71 | * frequency based on devfreq->min_freq/max_freq | ||
72 | */ | ||
73 | update_devfreq(devfreq); | 71 | update_devfreq(devfreq); |
74 | |||
75 | mutex_unlock(&devfreq->lock); | 72 | mutex_unlock(&devfreq->lock); |
76 | 73 | ||
77 | return NOTIFY_OK; | 74 | return NOTIFY_OK; |
@@ -143,8 +140,49 @@ static int gk20a_scale_target(struct device *dev, unsigned long *freq, | |||
143 | u32 flags) | 140 | u32 flags) |
144 | { | 141 | { |
145 | struct gk20a_platform *platform = dev_get_drvdata(dev); | 142 | struct gk20a_platform *platform = dev_get_drvdata(dev); |
146 | unsigned long rounded_rate = | 143 | struct gk20a *g = platform->g; |
147 | platform->clk_round_rate(dev, *freq); | 144 | struct gk20a_scale_profile *profile = g->scale_profile; |
145 | struct devfreq *devfreq = g->devfreq; | ||
146 | unsigned long local_freq = *freq; | ||
147 | unsigned long rounded_rate; | ||
148 | unsigned long min_freq = 0, max_freq = 0; | ||
149 | |||
150 | /* | ||
151 | * Calculate floor and cap frequency values | ||
152 | * | ||
153 | * Policy : | ||
154 | * We have two APIs to clip the frequency | ||
155 | * 1. devfreq | ||
156 | * 2. pm_qos | ||
157 | * | ||
158 | * To calculate floor (min) freq, we select MAX of floor frequencies | ||
159 | * requested from both APIs | ||
160 | * To get cap (max) freq, we select MIN of max frequencies | ||
161 | * | ||
162 | * In case we have conflict (min_freq > max_freq) after above | ||
163 | * steps, we ensure that devfreq->min_freq wins over | ||
164 | * qos_max_freq | ||
165 | */ | ||
166 | min_freq = max_t(u32, devfreq->min_freq, profile->qos_min_freq); | ||
167 | max_freq = min_t(u32, devfreq->max_freq, profile->qos_max_freq); | ||
168 | |||
169 | if (min_freq > max_freq) { | ||
170 | if (min_freq == devfreq->min_freq && | ||
171 | max_freq != devfreq->max_freq) { | ||
172 | max_freq = min_t(u32, min_freq, devfreq->max_freq); | ||
173 | } | ||
174 | min_freq = max_freq; | ||
175 | } | ||
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); | ||
148 | 186 | ||
149 | if (platform->clk_get_rate(dev) == rounded_rate) | 187 | if (platform->clk_get_rate(dev) == rounded_rate) |
150 | *freq = rounded_rate; | 188 | *freq = rounded_rate; |
@@ -332,6 +370,9 @@ void gk20a_scale_init(struct device *dev) | |||
332 | if (err || !profile->devfreq_profile.max_state) | 370 | if (err || !profile->devfreq_profile.max_state) |
333 | goto err_get_freqs; | 371 | goto err_get_freqs; |
334 | 372 | ||
373 | profile->qos_min_freq = 0; | ||
374 | profile->qos_max_freq = UINT_MAX; | ||
375 | |||
335 | /* Store device profile so we can access it if devfreq governor | 376 | /* Store device profile so we can access it if devfreq governor |
336 | * init needs that */ | 377 | * init needs that */ |
337 | g->scale_profile = profile; | 378 | g->scale_profile = profile; |
@@ -354,8 +395,6 @@ void gk20a_scale_init(struct device *dev) | |||
354 | devfreq = NULL; | 395 | devfreq = NULL; |
355 | 396 | ||
356 | g->devfreq = devfreq; | 397 | g->devfreq = devfreq; |
357 | g->devfreq_max_freq = devfreq->max_freq; | ||
358 | g->devfreq_min_freq = devfreq->min_freq; | ||
359 | } | 398 | } |
360 | 399 | ||
361 | /* Should we register QoS callback for this device? */ | 400 | /* Should we register QoS callback for this device? */ |
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_scale.h b/drivers/gpu/nvgpu/gk20a/gk20a_scale.h index 025c2070..c1e6fe86 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a_scale.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a_scale.h | |||
@@ -29,6 +29,8 @@ struct gk20a_scale_profile { | |||
29 | struct devfreq_dev_profile devfreq_profile; | 29 | struct devfreq_dev_profile devfreq_profile; |
30 | struct devfreq_dev_status dev_stat; | 30 | struct devfreq_dev_status dev_stat; |
31 | struct notifier_block qos_notify_block; | 31 | struct notifier_block qos_notify_block; |
32 | unsigned long qos_min_freq; | ||
33 | unsigned long qos_max_freq; | ||
32 | void *private_data; | 34 | void *private_data; |
33 | }; | 35 | }; |
34 | 36 | ||