Commit 0da611a8 authored by Christian König's avatar Christian König Committed by Luben Tuikov

dma-buf: add dma_fence_timestamp helper

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: default avatarYunxiang Li <Yunxiang.Li@amd.com>
Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Fixes: 1774baa6 ("drm/scheduler: Change scheduled fence track v2")
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
CC: stable@vger.kernel.org
Link: https://patchwork.freedesktop.org/patch/msgid/20230929104725.2358-1-christian.koenig@amd.com
parent 2fc1a50f
...@@ -76,16 +76,11 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, ...@@ -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,13 +268,10 @@ static int sync_fill_fence_info(struct dma_fence *fence, ...@@ -268,13 +268,10 @@ 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;
} }
......
...@@ -935,7 +935,7 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) ...@@ -935,7 +935,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);
} }
......
...@@ -568,6 +568,25 @@ static inline void dma_fence_set_error(struct dma_fence *fence, ...@@ -568,6 +568,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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment