diff options
Diffstat (limited to 'drivers/gpu/drm/drm_syncobj.c')
| -rw-r--r-- | drivers/gpu/drm/drm_syncobj.c | 70 | 
1 files changed, 54 insertions, 16 deletions
| diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 01da6789d044..84101baeecc6 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -126,6 +126,11 @@   * synchronize between the two.   * This requirement is inherited from the Vulkan fence API.   * + * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE is set, the ioctl will also set + * a fence deadline hint on the backing fences before waiting, to provide the + * fence signaler with an appropriate sense of urgency.  The deadline is + * specified as an absolute &CLOCK_MONOTONIC value in units of ns. + *   * Similarly, &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT takes an array of syncobj   * handles as well as an array of u64 points and does a host-side wait on all   * of syncobj fences at the given points simultaneously. @@ -1027,7 +1032,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,  						  uint32_t count,  						  uint32_t flags,  						  signed long timeout, -						  uint32_t *idx) +						  uint32_t *idx, +						  ktime_t *deadline)  {  	struct syncobj_wait_entry *entries;  	struct dma_fence *fence; @@ -1108,6 +1114,15 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,  			drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]);  	} +	if (deadline) { +		for (i = 0; i < count; ++i) { +			fence = entries[i].fence; +			if (!fence) +				continue; +			dma_fence_set_deadline(fence, *deadline); +		} +	} +  	do {  		set_current_state(TASK_INTERRUPTIBLE); @@ -1206,7 +1221,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev,  				  struct drm_file *file_private,  				  struct drm_syncobj_wait *wait,  				  struct drm_syncobj_timeline_wait *timeline_wait, -				  struct drm_syncobj **syncobjs, bool timeline) +				  struct drm_syncobj **syncobjs, bool timeline, +				  ktime_t *deadline)  {  	signed long timeout = 0;  	uint32_t first = ~0; @@ -1217,7 +1233,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev,  							 NULL,  							 wait->count_handles,  							 wait->flags, -							 timeout, &first); +							 timeout, &first, +							 deadline);  		if (timeout < 0)  			return timeout;  		wait->first_signaled = first; @@ -1227,7 +1244,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev,  							 u64_to_user_ptr(timeline_wait->points),  							 timeline_wait->count_handles,  							 timeline_wait->flags, -							 timeout, &first); +							 timeout, &first, +							 deadline);  		if (timeout < 0)  			return timeout;  		timeline_wait->first_signaled = first; @@ -1298,17 +1316,22 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,  {  	struct drm_syncobj_wait *args = data;  	struct drm_syncobj **syncobjs; +	unsigned int possible_flags; +	ktime_t t, *tp = NULL;  	int ret = 0;  	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))  		return -EOPNOTSUPP; -	if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | -			    DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)) +	possible_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | +			 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | +			 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE; + +	if (args->flags & ~possible_flags)  		return -EINVAL;  	if (args->count_handles == 0) -		return -EINVAL; +		return 0;  	ret = drm_syncobj_array_find(file_private,  				     u64_to_user_ptr(args->handles), @@ -1317,8 +1340,13 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,  	if (ret < 0)  		return ret; +	if (args->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE) { +		t = ns_to_ktime(args->deadline_nsec); +		tp = &t; +	} +  	ret = drm_syncobj_array_wait(dev, file_private, -				     args, NULL, syncobjs, false); +				     args, NULL, syncobjs, false, tp);  	drm_syncobj_array_free(syncobjs, args->count_handles); @@ -1331,18 +1359,23 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,  {  	struct drm_syncobj_timeline_wait *args = data;  	struct drm_syncobj **syncobjs; +	unsigned int possible_flags; +	ktime_t t, *tp = NULL;  	int ret = 0;  	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))  		return -EOPNOTSUPP; -	if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | -			    DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | -			    DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) +	possible_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | +			 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | +			 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE | +			 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE; + +	if (args->flags & ~possible_flags)  		return -EINVAL;  	if (args->count_handles == 0) -		return -EINVAL; +		return 0;  	ret = drm_syncobj_array_find(file_private,  				     u64_to_user_ptr(args->handles), @@ -1351,8 +1384,13 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,  	if (ret < 0)  		return ret; +	if (args->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE) { +		t = ns_to_ktime(args->deadline_nsec); +		tp = &t; +	} +  	ret = drm_syncobj_array_wait(dev, file_private, -				     NULL, args, syncobjs, true); +				     NULL, args, syncobjs, true, tp);  	drm_syncobj_array_free(syncobjs, args->count_handles); @@ -1365,7 +1403,7 @@ static void syncobj_eventfd_entry_fence_func(struct dma_fence *fence,  	struct syncobj_eventfd_entry *entry =  		container_of(cb, struct syncobj_eventfd_entry, fence_cb); -	eventfd_signal(entry->ev_fd_ctx, 1); +	eventfd_signal(entry->ev_fd_ctx);  	syncobj_eventfd_entry_free(entry);  } @@ -1388,13 +1426,13 @@ syncobj_eventfd_entry_func(struct drm_syncobj *syncobj,  	entry->fence = fence;  	if (entry->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) { -		eventfd_signal(entry->ev_fd_ctx, 1); +		eventfd_signal(entry->ev_fd_ctx);  		syncobj_eventfd_entry_free(entry);  	} else {  		ret = dma_fence_add_callback(fence, &entry->fence_cb,  					     syncobj_eventfd_entry_fence_func);  		if (ret == -ENOENT) { -			eventfd_signal(entry->ev_fd_ctx, 1); +			eventfd_signal(entry->ev_fd_ctx);  			syncobj_eventfd_entry_free(entry);  		}  	} | 
