dma-buf: add dma_fence_timestamp helper
commit b83ce9cb4a465b8f9a3fa45561b721a9551f60e3 upstream. When a fence signals there is a very small race window where the timestamp isn't updated yet. sync_file solves this by busy waiting for the timestamp to appear, but on other ocassions didn't handled this correctly. Provide a dma_fence_timestamp() helper function for this and use it in all appropriate cases. Another alternative would be to grab the spinlock when that happens. v2 by teddy: add a wait parameter to wait for the timestamp to show up, in case the accurate timestamp is needed and/or the timestamp is not based on ktime (e.g. hw timestamp) v3 chk: drop the parameter again for unified handling Signed-off-by: Yunxiang Li <Yunxiang.Li@amd.com> Signed-off-by: Christian König <christian.koenig@amd.com> Fixes: 1774baa64f93 ("drm/scheduler: Change scheduled fence track v2") Reviewed-by: Alex Deucher <alexander.deucher@amd.com> CC: stable@vger.kernel.org Link: https://patchwork.freedesktop.org/patch/msgid/20230929104725.2358-1-christian.koenig@amd.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
cb8f1dd1b7
commit
d67b5a2b97
@ -76,16 +76,11 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
|
|||||||
dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
|
dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
|
||||||
if (!dma_fence_is_signaled(tmp)) {
|
if (!dma_fence_is_signaled(tmp)) {
|
||||||
++count;
|
++count;
|
||||||
} else if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT,
|
|
||||||
&tmp->flags)) {
|
|
||||||
if (ktime_after(tmp->timestamp, timestamp))
|
|
||||||
timestamp = tmp->timestamp;
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
ktime_t t = dma_fence_timestamp(tmp);
|
||||||
* Use the current time if the fence is
|
|
||||||
* currently signaling.
|
if (ktime_after(t, timestamp))
|
||||||
*/
|
timestamp = t;
|
||||||
timestamp = ktime_get();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,12 +268,9 @@ static int sync_fill_fence_info(struct dma_fence *fence,
|
|||||||
sizeof(info->driver_name));
|
sizeof(info->driver_name));
|
||||||
|
|
||||||
info->status = dma_fence_get_status(fence);
|
info->status = dma_fence_get_status(fence);
|
||||||
while (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) &&
|
|
||||||
!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
|
|
||||||
cpu_relax();
|
|
||||||
info->timestamp_ns =
|
info->timestamp_ns =
|
||||||
test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags) ?
|
dma_fence_is_signaled(fence) ?
|
||||||
ktime_to_ns(fence->timestamp) :
|
ktime_to_ns(dma_fence_timestamp(fence)) :
|
||||||
ktime_set(0, 0);
|
ktime_set(0, 0);
|
||||||
|
|
||||||
return info->status;
|
return info->status;
|
||||||
|
@ -841,7 +841,7 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched)
|
|||||||
|
|
||||||
if (next) {
|
if (next) {
|
||||||
next->s_fence->scheduled.timestamp =
|
next->s_fence->scheduled.timestamp =
|
||||||
job->s_fence->finished.timestamp;
|
dma_fence_timestamp(&job->s_fence->finished);
|
||||||
/* start TO timer for next job */
|
/* start TO timer for next job */
|
||||||
drm_sched_start_timeout(sched);
|
drm_sched_start_timeout(sched);
|
||||||
}
|
}
|
||||||
|
@ -548,6 +548,25 @@ static inline void dma_fence_set_error(struct dma_fence *fence,
|
|||||||
fence->error = error;
|
fence->error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dma_fence_timestamp - helper to get the completion timestamp of a fence
|
||||||
|
* @fence: fence to get the timestamp from.
|
||||||
|
*
|
||||||
|
* After a fence is signaled the timestamp is updated with the signaling time,
|
||||||
|
* but setting the timestamp can race with tasks waiting for the signaling. This
|
||||||
|
* helper busy waits for the correct timestamp to appear.
|
||||||
|
*/
|
||||||
|
static inline ktime_t dma_fence_timestamp(struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
if (WARN_ON(!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)))
|
||||||
|
return ktime_get();
|
||||||
|
|
||||||
|
while (!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
|
||||||
|
cpu_relax();
|
||||||
|
|
||||||
|
return fence->timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
signed long dma_fence_wait_timeout(struct dma_fence *,
|
signed long dma_fence_wait_timeout(struct dma_fence *,
|
||||||
bool intr, signed long timeout);
|
bool intr, signed long timeout);
|
||||||
signed long dma_fence_wait_any_timeout(struct dma_fence **fences,
|
signed long dma_fence_wait_any_timeout(struct dma_fence **fences,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user