aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSharat Masetty <smasetty@codeaurora.org>2018-11-29 05:05:20 -0500
committerAlex Deucher <alexander.deucher@amd.com>2018-12-05 17:56:16 -0500
commit1db8c142b6c557a951e8f9866b98953fe91cbdd6 (patch)
treee93983882976af32506fdde4336f930c1fb761d8
parent9afd07566b6c908324cb4072102e2ce96bce986a (diff)
drm/scheduler: Add drm_sched_suspend/resume_timeout()
This patch adds two new functions to help client drivers suspend and resume the scheduler job timeout. This can be useful in cases where the hardware has preemption support enabled. Using this, it is possible to have the timeout active only for the ring which is active on the ringbuffer. This patch also makes the job_list_lock IRQ safe. Suggested-by: Christian Koenig <Christian.Koenig@amd.com> Signed-off-by: Sharat Masetty <smasetty@codeaurora.org> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_dump.c9
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c85
-rw-r--r--include/drm/gpu_scheduler.h4
3 files changed, 82 insertions, 16 deletions
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
index 9146e30e24a6..fd6bad2100cf 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
@@ -118,6 +118,7 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
118 unsigned int n_obj, n_bomap_pages; 118 unsigned int n_obj, n_bomap_pages;
119 size_t file_size, mmu_size; 119 size_t file_size, mmu_size;
120 __le64 *bomap, *bomap_start; 120 __le64 *bomap, *bomap_start;
121 unsigned long flags;
121 122
122 /* Only catch the first event, or when manually re-armed */ 123 /* Only catch the first event, or when manually re-armed */
123 if (!etnaviv_dump_core) 124 if (!etnaviv_dump_core)
@@ -134,13 +135,13 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
134 mmu_size + gpu->buffer.size; 135 mmu_size + gpu->buffer.size;
135 136
136 /* Add in the active command buffers */ 137 /* Add in the active command buffers */
137 spin_lock(&gpu->sched.job_list_lock); 138 spin_lock_irqsave(&sched->job_list_lock, flags);
138 list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { 139 list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) {
139 submit = to_etnaviv_submit(s_job); 140 submit = to_etnaviv_submit(s_job);
140 file_size += submit->cmdbuf.size; 141 file_size += submit->cmdbuf.size;
141 n_obj++; 142 n_obj++;
142 } 143 }
143 spin_unlock(&gpu->sched.job_list_lock); 144 spin_unlock_irqrestore(&sched->job_list_lock, flags);
144 145
145 /* Add in the active buffer objects */ 146 /* Add in the active buffer objects */
146 list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) { 147 list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
@@ -182,14 +183,14 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
182 gpu->buffer.size, 183 gpu->buffer.size,
183 etnaviv_cmdbuf_get_va(&gpu->buffer)); 184 etnaviv_cmdbuf_get_va(&gpu->buffer));
184 185
185 spin_lock(&gpu->sched.job_list_lock); 186 spin_lock_irqsave(&sched->job_list_lock, flags);
186 list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { 187 list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) {
187 submit = to_etnaviv_submit(s_job); 188 submit = to_etnaviv_submit(s_job);
188 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, 189 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD,
189 submit->cmdbuf.vaddr, submit->cmdbuf.size, 190 submit->cmdbuf.vaddr, submit->cmdbuf.size,
190 etnaviv_cmdbuf_get_va(&submit->cmdbuf)); 191 etnaviv_cmdbuf_get_va(&submit->cmdbuf));
191 } 192 }
192 spin_unlock(&gpu->sched.job_list_lock); 193 spin_unlock_irqrestore(&sched->job_list_lock, flags);
193 194
194 /* Reserve space for the bomap */ 195 /* Reserve space for the bomap */
195 if (n_bomap_pages) { 196 if (n_bomap_pages) {
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index 05b803d1248d..dbb69063b3d5 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -211,6 +211,62 @@ void drm_sched_fault(struct drm_gpu_scheduler *sched)
211} 211}
212EXPORT_SYMBOL(drm_sched_fault); 212EXPORT_SYMBOL(drm_sched_fault);
213 213
214/**
215 * drm_sched_suspend_timeout - Suspend scheduler job timeout
216 *
217 * @sched: scheduler instance for which to suspend the timeout
218 *
219 * Suspend the delayed work timeout for the scheduler. This is done by
220 * modifying the delayed work timeout to an arbitrary large value,
221 * MAX_SCHEDULE_TIMEOUT in this case. Note that this function can be
222 * called from an IRQ context.
223 *
224 * Returns the timeout remaining
225 *
226 */
227unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched)
228{
229 unsigned long sched_timeout, now = jiffies;
230
231 sched_timeout = sched->work_tdr.timer.expires;
232
233 /*
234 * Modify the timeout to an arbitrarily large value. This also prevents
235 * the timeout to be restarted when new submissions arrive
236 */
237 if (mod_delayed_work(system_wq, &sched->work_tdr, MAX_SCHEDULE_TIMEOUT)
238 && time_after(sched_timeout, now))
239 return sched_timeout - now;
240 else
241 return sched->timeout;
242}
243EXPORT_SYMBOL(drm_sched_suspend_timeout);
244
245/**
246 * drm_sched_resume_timeout - Resume scheduler job timeout
247 *
248 * @sched: scheduler instance for which to resume the timeout
249 * @remaining: remaining timeout
250 *
251 * Resume the delayed work timeout for the scheduler. Note that
252 * this function can be called from an IRQ context.
253 */
254void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched,
255 unsigned long remaining)
256{
257 unsigned long flags;
258
259 spin_lock_irqsave(&sched->job_list_lock, flags);
260
261 if (list_empty(&sched->ring_mirror_list))
262 cancel_delayed_work(&sched->work_tdr);
263 else
264 mod_delayed_work(system_wq, &sched->work_tdr, remaining);
265
266 spin_unlock_irqrestore(&sched->job_list_lock, flags);
267}
268EXPORT_SYMBOL(drm_sched_resume_timeout);
269
214/* job_finish is called after hw fence signaled 270/* job_finish is called after hw fence signaled
215 */ 271 */
216static void drm_sched_job_finish(struct work_struct *work) 272static void drm_sched_job_finish(struct work_struct *work)
@@ -218,6 +274,7 @@ static void drm_sched_job_finish(struct work_struct *work)
218 struct drm_sched_job *s_job = container_of(work, struct drm_sched_job, 274 struct drm_sched_job *s_job = container_of(work, struct drm_sched_job,
219 finish_work); 275 finish_work);
220 struct drm_gpu_scheduler *sched = s_job->sched; 276 struct drm_gpu_scheduler *sched = s_job->sched;
277 unsigned long flags;
221 278
222 /* 279 /*
223 * Canceling the timeout without removing our job from the ring mirror 280 * Canceling the timeout without removing our job from the ring mirror
@@ -228,12 +285,12 @@ static void drm_sched_job_finish(struct work_struct *work)
228 */ 285 */
229 cancel_delayed_work_sync(&sched->work_tdr); 286 cancel_delayed_work_sync(&sched->work_tdr);
230 287
231 spin_lock(&sched->job_list_lock); 288 spin_lock_irqsave(&sched->job_list_lock, flags);
232 /* remove job from ring_mirror_list */ 289 /* remove job from ring_mirror_list */
233 list_del_init(&s_job->node); 290 list_del_init(&s_job->node);
234 /* queue TDR for next job */ 291 /* queue TDR for next job */
235 drm_sched_start_timeout(sched); 292 drm_sched_start_timeout(sched);
236 spin_unlock(&sched->job_list_lock); 293 spin_unlock_irqrestore(&sched->job_list_lock, flags);
237 294
238 sched->ops->free_job(s_job); 295 sched->ops->free_job(s_job);
239} 296}
@@ -249,20 +306,22 @@ static void drm_sched_job_finish_cb(struct dma_fence *f,
249static void drm_sched_job_begin(struct drm_sched_job *s_job) 306static void drm_sched_job_begin(struct drm_sched_job *s_job)
250{ 307{
251 struct drm_gpu_scheduler *sched = s_job->sched; 308 struct drm_gpu_scheduler *sched = s_job->sched;
309 unsigned long flags;
252 310
253 dma_fence_add_callback(&s_job->s_fence->finished, &s_job->finish_cb, 311 dma_fence_add_callback(&s_job->s_fence->finished, &s_job->finish_cb,
254 drm_sched_job_finish_cb); 312 drm_sched_job_finish_cb);
255 313
256 spin_lock(&sched->job_list_lock); 314 spin_lock_irqsave(&sched->job_list_lock, flags);
257 list_add_tail(&s_job->node, &sched->ring_mirror_list); 315 list_add_tail(&s_job->node, &sched->ring_mirror_list);
258 drm_sched_start_timeout(sched); 316 drm_sched_start_timeout(sched);
259 spin_unlock(&sched->job_list_lock); 317 spin_unlock_irqrestore(&sched->job_list_lock, flags);
260} 318}
261 319
262static void drm_sched_job_timedout(struct work_struct *work) 320static void drm_sched_job_timedout(struct work_struct *work)
263{ 321{
264 struct drm_gpu_scheduler *sched; 322 struct drm_gpu_scheduler *sched;
265 struct drm_sched_job *job; 323 struct drm_sched_job *job;
324 unsigned long flags;
266 325
267 sched = container_of(work, struct drm_gpu_scheduler, work_tdr.work); 326 sched = container_of(work, struct drm_gpu_scheduler, work_tdr.work);
268 job = list_first_entry_or_null(&sched->ring_mirror_list, 327 job = list_first_entry_or_null(&sched->ring_mirror_list,
@@ -271,9 +330,9 @@ static void drm_sched_job_timedout(struct work_struct *work)
271 if (job) 330 if (job)
272 job->sched->ops->timedout_job(job); 331 job->sched->ops->timedout_job(job);
273 332
274 spin_lock(&sched->job_list_lock); 333 spin_lock_irqsave(&sched->job_list_lock, flags);
275 drm_sched_start_timeout(sched); 334 drm_sched_start_timeout(sched);
276 spin_unlock(&sched->job_list_lock); 335 spin_unlock_irqrestore(&sched->job_list_lock, flags);
277} 336}
278 337
279/** 338/**
@@ -287,9 +346,10 @@ void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_jo
287{ 346{
288 struct drm_sched_job *s_job; 347 struct drm_sched_job *s_job;
289 struct drm_sched_entity *entity, *tmp; 348 struct drm_sched_entity *entity, *tmp;
349 unsigned long flags;
290 int i; 350 int i;
291 351
292 spin_lock(&sched->job_list_lock); 352 spin_lock_irqsave(&sched->job_list_lock, flags);
293 list_for_each_entry_reverse(s_job, &sched->ring_mirror_list, node) { 353 list_for_each_entry_reverse(s_job, &sched->ring_mirror_list, node) {
294 if (s_job->s_fence->parent && 354 if (s_job->s_fence->parent &&
295 dma_fence_remove_callback(s_job->s_fence->parent, 355 dma_fence_remove_callback(s_job->s_fence->parent,
@@ -299,7 +359,7 @@ void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_jo
299 atomic_dec(&sched->hw_rq_count); 359 atomic_dec(&sched->hw_rq_count);
300 } 360 }
301 } 361 }
302 spin_unlock(&sched->job_list_lock); 362 spin_unlock_irqrestore(&sched->job_list_lock, flags);
303 363
304 if (bad && bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) { 364 if (bad && bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
305 atomic_inc(&bad->karma); 365 atomic_inc(&bad->karma);
@@ -337,9 +397,10 @@ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched)
337{ 397{
338 struct drm_sched_job *s_job, *tmp; 398 struct drm_sched_job *s_job, *tmp;
339 bool found_guilty = false; 399 bool found_guilty = false;
400 unsigned long flags;
340 int r; 401 int r;
341 402
342 spin_lock(&sched->job_list_lock); 403 spin_lock_irqsave(&sched->job_list_lock, flags);
343 list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) { 404 list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) {
344 struct drm_sched_fence *s_fence = s_job->s_fence; 405 struct drm_sched_fence *s_fence = s_job->s_fence;
345 struct dma_fence *fence; 406 struct dma_fence *fence;
@@ -353,7 +414,7 @@ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched)
353 if (found_guilty && s_job->s_fence->scheduled.context == guilty_context) 414 if (found_guilty && s_job->s_fence->scheduled.context == guilty_context)
354 dma_fence_set_error(&s_fence->finished, -ECANCELED); 415 dma_fence_set_error(&s_fence->finished, -ECANCELED);
355 416
356 spin_unlock(&sched->job_list_lock); 417 spin_unlock_irqrestore(&sched->job_list_lock, flags);
357 fence = sched->ops->run_job(s_job); 418 fence = sched->ops->run_job(s_job);
358 atomic_inc(&sched->hw_rq_count); 419 atomic_inc(&sched->hw_rq_count);
359 420
@@ -372,10 +433,10 @@ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched)
372 drm_sched_expel_job_unlocked(s_job); 433 drm_sched_expel_job_unlocked(s_job);
373 drm_sched_process_job(NULL, &s_fence->cb); 434 drm_sched_process_job(NULL, &s_fence->cb);
374 } 435 }
375 spin_lock(&sched->job_list_lock); 436 spin_lock_irqsave(&sched->job_list_lock, flags);
376 } 437 }
377 drm_sched_start_timeout(sched); 438 drm_sched_start_timeout(sched);
378 spin_unlock(&sched->job_list_lock); 439 spin_unlock_irqrestore(&sched->job_list_lock, flags);
379} 440}
380EXPORT_SYMBOL(drm_sched_job_recovery); 441EXPORT_SYMBOL(drm_sched_job_recovery);
381 442
diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h
index 926379d53484..47e19796c450 100644
--- a/include/drm/gpu_scheduler.h
+++ b/include/drm/gpu_scheduler.h
@@ -331,4 +331,8 @@ struct drm_sched_fence *drm_sched_fence_create(
331void drm_sched_fence_scheduled(struct drm_sched_fence *fence); 331void drm_sched_fence_scheduled(struct drm_sched_fence *fence);
332void drm_sched_fence_finished(struct drm_sched_fence *fence); 332void drm_sched_fence_finished(struct drm_sched_fence *fence);
333 333
334unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched);
335void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched,
336 unsigned long remaining);
337
334#endif 338#endif