mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: Yunxiang Li <Yunxiang.Li@amd.com>
Signed-off-by: Christian König <christian.koenig@amd.com>
Fixes: 1774baa64f ("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
			
			
This commit is contained in:
		
							parent
							
								
									2fc1a50fa4
								
							
						
					
					
						commit
						0da611a870
					
				
					 4 changed files with 27 additions and 16 deletions
				
			
		| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
	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…
	
		Reference in a new issue