Skip to content

Commit db8b496

Browse files
committed
drm/sched: Call drm_sched_fence_set_parent() from drm_sched_fence_scheduled()
Drivers that can delegate waits to the firmware/GPU pass the scheduled fence to drm_sched_job_add_dependency(), and issue wait commands to the firmware/GPU at job submission time. For this to be possible, they need all their 'native' dependencies to have a valid parent since this is where the actual HW fence information are encoded. In drm_sched_main(), we currently call drm_sched_fence_set_parent() after drm_sched_fence_scheduled(), leaving a short period of time during which the job depending on this fence can be submitted. Since setting parent and signaling the fence are two things that are kinda related (you can't have a parent if the job hasn't been scheduled), it probably makes sense to pass the parent fence to drm_sched_fence_scheduled() and let it call drm_sched_fence_set_parent() before it signals the scheduled fence. Here is a detailed description of the race we are fixing here: Thread A Thread B - calls drm_sched_fence_scheduled() - signals s_fence->scheduled which wakes up thread B - entity dep signaled, checking the next dep - no more deps waiting - entity is picked for job submission by drm_gpu_scheduler - run_job() is called - run_job() tries to collect native fence info from s_fence->parent, but it's NULL => BOOM, we can't do our native wait - calls drm_sched_fence_set_parent() v2: * Fix commit message v3: * Add a detailed description of the race to the commit message * Add Luben's R-b Signed-off-by: Boris Brezillon <[email protected]> Cc: Frank Binns <[email protected]> Cc: Sarah Walker <[email protected]> Cc: Donald Robson <[email protected]> Cc: Luben Tuikov <[email protected]> Cc: David Airlie <[email protected]> Cc: Daniel Vetter <[email protected]> Cc: Sumit Semwal <[email protected]> Cc: "Christian König" <[email protected]> Reviewed-by: Luben Tuikov <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 8fb3e25 commit db8b496

File tree

3 files changed

+28
-20
lines changed

3 files changed

+28
-20
lines changed

drivers/gpu/drm/scheduler/sched_fence.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,32 @@ static void __exit drm_sched_fence_slab_fini(void)
4848
kmem_cache_destroy(sched_fence_slab);
4949
}
5050

51-
void drm_sched_fence_scheduled(struct drm_sched_fence *fence)
51+
static void drm_sched_fence_set_parent(struct drm_sched_fence *s_fence,
52+
struct dma_fence *fence)
5253
{
54+
/*
55+
* smp_store_release() to ensure another thread racing us
56+
* in drm_sched_fence_set_deadline_finished() sees the
57+
* fence's parent set before test_bit()
58+
*/
59+
smp_store_release(&s_fence->parent, dma_fence_get(fence));
60+
if (test_bit(DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT,
61+
&s_fence->finished.flags))
62+
dma_fence_set_deadline(fence, s_fence->deadline);
63+
}
64+
65+
void drm_sched_fence_scheduled(struct drm_sched_fence *fence,
66+
struct dma_fence *parent)
67+
{
68+
/* Set the parent before signaling the scheduled fence, such that,
69+
* any waiter expecting the parent to be filled after the job has
70+
* been scheduled (which is the case for drivers delegating waits
71+
* to some firmware) doesn't have to busy wait for parent to show
72+
* up.
73+
*/
74+
if (!IS_ERR_OR_NULL(parent))
75+
drm_sched_fence_set_parent(fence, parent);
76+
5377
dma_fence_signal(&fence->scheduled);
5478
}
5579

@@ -179,20 +203,6 @@ struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f)
179203
}
180204
EXPORT_SYMBOL(to_drm_sched_fence);
181205

182-
void drm_sched_fence_set_parent(struct drm_sched_fence *s_fence,
183-
struct dma_fence *fence)
184-
{
185-
/*
186-
* smp_store_release() to ensure another thread racing us
187-
* in drm_sched_fence_set_deadline_finished() sees the
188-
* fence's parent set before test_bit()
189-
*/
190-
smp_store_release(&s_fence->parent, dma_fence_get(fence));
191-
if (test_bit(DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT,
192-
&s_fence->finished.flags))
193-
dma_fence_set_deadline(fence, s_fence->deadline);
194-
}
195-
196206
struct drm_sched_fence *drm_sched_fence_alloc(struct drm_sched_entity *entity,
197207
void *owner)
198208
{

drivers/gpu/drm/scheduler/sched_main.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,10 +1040,9 @@ static int drm_sched_main(void *param)
10401040
trace_drm_run_job(sched_job, entity);
10411041
fence = sched->ops->run_job(sched_job);
10421042
complete_all(&entity->entity_idle);
1043-
drm_sched_fence_scheduled(s_fence);
1043+
drm_sched_fence_scheduled(s_fence, fence);
10441044

10451045
if (!IS_ERR_OR_NULL(fence)) {
1046-
drm_sched_fence_set_parent(s_fence, fence);
10471046
/* Drop for original kref_init of the fence */
10481047
dma_fence_put(fence);
10491048

include/drm/gpu_scheduler.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -582,15 +582,14 @@ void drm_sched_entity_set_priority(struct drm_sched_entity *entity,
582582
enum drm_sched_priority priority);
583583
bool drm_sched_entity_is_ready(struct drm_sched_entity *entity);
584584

585-
void drm_sched_fence_set_parent(struct drm_sched_fence *s_fence,
586-
struct dma_fence *fence);
587585
struct drm_sched_fence *drm_sched_fence_alloc(
588586
struct drm_sched_entity *s_entity, void *owner);
589587
void drm_sched_fence_init(struct drm_sched_fence *fence,
590588
struct drm_sched_entity *entity);
591589
void drm_sched_fence_free(struct drm_sched_fence *fence);
592590

593-
void drm_sched_fence_scheduled(struct drm_sched_fence *fence);
591+
void drm_sched_fence_scheduled(struct drm_sched_fence *fence,
592+
struct dma_fence *parent);
594593
void drm_sched_fence_finished(struct drm_sched_fence *fence);
595594

596595
unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched);

0 commit comments

Comments
 (0)