Hopefully addressing most of these in the upcoming set, some comments below.
+/**
- drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
- @timeout_ns: timeout in ns
- Calculate the timeout in jiffies from an absolute timeout in ns.
- */
+unsigned long drm_timeout_abs_to_jiffies(uint64_t timeout_ns)
Not in any header or otherwise exported, so static?
Done.
/* clamp timeout to avoid unsigned-> signed overflow */
if (timeout_jiffies > MAX_SCHEDULE_TIMEOUT )
return MAX_SCHEDULE_TIMEOUT - 1;
This about avoiding the conversion into an infinite timeout, right? I think the comment is misleading (certainly doesn't explain MAX_SCHEDULE_TIMEOUT-1) and the test should be >= MAX_SCHEDULE_TIMEOUT.
Taken from AMD code, but I see your logic, I've adjust the code and added the one as requested.
return timeout_jiffies;
Timeouts tend to use timeout_jiffies + 1 to avoid the timer interrupt screwing up the calculation, or just generally returning a fraction too early.
+}
+static int drm_syncobj_wait_all_fences(struct drm_device *dev,
struct drm_file *file_private,
struct drm_syncobj_wait *wait,
uint32_t *handles)
+{
uint32_t i;
int ret;
unsigned long timeout = drm_timeout_abs_to_jiffies(wait->timeout_ns);
Also note that this doesn't handle timeout = 0 very gracefully with multiple fences. (dma_fence_wait_timeout will convert that on return to 1). Hmm, by using an absolute timeout we can't pass into timeout=0 to do a poll.
I've decdied to make timeout = 0 be poll, I can't see anyone having a realtime clock of 0 making sense anyways.
There is a fix in flight for dma_fence_wait_timeout doing that, it's in drm-next now.
&fence);
if (ret)
return ret;
if (!fence)
continue;
I thought no fence for the syncobj was the *unsignaled* case, and to wait upon it was a user error. I second Jason's idea to make the lookup and error checking on the fences uniform between WAIT_ALL and WAIT_ANY.
ret = dma_fence_wait_timeout(fence, true, timeout);
dma_fence_put(fence);
if (ret < 0)
return ret;
if (ret == 0)
break;
timeout = ret;
}
wait->out_timeout_ns = jiffies_to_nsecs(ret);
wait->out_status = (ret > 0);
wait->first_signaled = 0;
return 0;
+}
+static int drm_syncobj_wait_any_fence(struct drm_device *dev,
struct drm_file *file_private,
struct drm_syncobj_wait *wait,
uint32_t *handles)
+{
unsigned long timeout = drm_timeout_abs_to_jiffies(wait->timeout_ns);
struct dma_fence **array;
uint32_t i;
int ret;
uint32_t first = ~0;
/* Prepare the fence array */
array = kcalloc(wait->count_handles,
sizeof(struct dma_fence *), GFP_KERNEL);
if (array == NULL)
return -ENOMEM;
for (i = 0; i < wait->count_handles; i++) {
struct dma_fence *fence;
ret = drm_syncobj_fence_get(file_private, handles[i],
&fence);
if (ret)
goto err_free_fence_array;
else if (fence)
array[i] = fence;
else { /* NULL, the fence has been already signaled */
ret = 1;
goto out;
}
}
ret = dma_fence_wait_any_timeout(array, wait->count_handles, true, timeout,
&first);
if (ret < 0)
goto err_free_fence_array;
+out:
wait->out_timeout_ns = jiffies_to_nsecs(ret);
wait->out_status = (ret > 0);
Didn't the amdgpu interface report which fence completed first? (I may be imagining that.)
Just below your comment down there is first_signaled getting assigned!
wait->first_signaled = first;
/* set return value 0 to indicate success */
ret = 0;
+err_free_fence_array:
for (i = 0; i < wait->count_handles; i++)
dma_fence_put(array[i]);
kfree(array);
return ret;
+}
+int +drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_private)
+{
struct drm_syncobj_wait *args = data;
uint32_t *handles;
int ret = 0;
if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
return -ENODEV;
if (args->flags != 0 && args->flags != DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)
return -EINVAL;
if (args->count_handles == 0)
return 0;
Hmm, returning success without updating any of the status fields. -EINVAL? -ENOTHINGTODO.
Done, -EINVAL is its.
Otherwise I've pretty much done what Jason asked, gathered all the fences before waiting, and then waited,
Will resend new patch shortly.
Dave.