summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/xe/xe_wait_user_fence.c47
-rw-r--r--include/uapi/drm/xe_drm.h16
2 files changed, 51 insertions, 12 deletions
diff --git a/drivers/gpu/drm/xe/xe_wait_user_fence.c b/drivers/gpu/drm/xe/xe_wait_user_fence.c
index 098e2a4cff3f..c4420c0dbf9c 100644
--- a/drivers/gpu/drm/xe/xe_wait_user_fence.c
+++ b/drivers/gpu/drm/xe/xe_wait_user_fence.c
@@ -7,6 +7,7 @@
#include <drm/drm_device.h>
#include <drm/drm_file.h>
+#include <drm/drm_utils.h>
#include <drm/xe_drm.h>
#include "xe_device.h"
@@ -84,6 +85,21 @@ static int check_hw_engines(struct xe_device *xe,
DRM_XE_UFENCE_WAIT_VM_ERROR)
#define MAX_OP DRM_XE_UFENCE_WAIT_LTE
+static unsigned long to_jiffies_timeout(struct drm_xe_wait_user_fence *args)
+{
+ unsigned long timeout;
+
+ if (args->flags & DRM_XE_UFENCE_WAIT_ABSTIME)
+ return drm_timeout_abs_to_jiffies(args->timeout);
+
+ if (args->timeout == MAX_SCHEDULE_TIMEOUT || args->timeout == 0)
+ return args->timeout;
+
+ timeout = nsecs_to_jiffies(args->timeout);
+
+ return timeout ?: 1;
+}
+
int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
@@ -98,7 +114,8 @@ int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data,
int err;
bool no_engines = args->flags & DRM_XE_UFENCE_WAIT_SOFT_OP ||
args->flags & DRM_XE_UFENCE_WAIT_VM_ERROR;
- unsigned long timeout = args->timeout;
+ unsigned long timeout;
+ ktime_t start;
if (XE_IOCTL_ERR(xe, args->extensions) || XE_IOCTL_ERR(xe, args->pad) ||
XE_IOCTL_ERR(xe, args->reserved[0] || args->reserved[1]))
@@ -152,8 +169,18 @@ int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data,
addr = vm->async_ops.error_capture.addr;
}
- if (XE_IOCTL_ERR(xe, timeout > MAX_SCHEDULE_TIMEOUT))
- return -EINVAL;
+ /*
+ * For negative timeout we want to wait "forever" by setting
+ * MAX_SCHEDULE_TIMEOUT. But we have to assign this value also
+ * to args->timeout to avoid being zeroed on the signal delivery
+ * (see arithmetics after wait).
+ */
+ if (args->timeout < 0)
+ args->timeout = MAX_SCHEDULE_TIMEOUT;
+
+ timeout = to_jiffies_timeout(args);
+
+ start = ktime_get();
/*
* FIXME: Very simple implementation at the moment, single wait queue
@@ -192,17 +219,17 @@ int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data,
} else {
remove_wait_queue(&xe->ufence_wq, &w_wait);
}
+
+ if (!(args->flags & DRM_XE_UFENCE_WAIT_ABSTIME)) {
+ args->timeout -= ktime_to_ns(ktime_sub(ktime_get(), start));
+ if (args->timeout < 0)
+ args->timeout = 0;
+ }
+
if (XE_IOCTL_ERR(xe, err < 0))
return err;
else if (XE_IOCTL_ERR(xe, !timeout))
return -ETIME;
- /*
- * Again very simple, return the time in jiffies that has past, may need
- * a more precision
- */
- if (args->flags & DRM_XE_UFENCE_WAIT_ABSTIME)
- args->timeout = args->timeout - timeout;
-
return 0;
}
diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
index 8e7be1551333..347351a8f618 100644
--- a/include/uapi/drm/xe_drm.h
+++ b/include/uapi/drm/xe_drm.h
@@ -904,8 +904,20 @@ struct drm_xe_wait_user_fence {
#define DRM_XE_UFENCE_WAIT_U64 0xffffffffffffffffu
/** @mask: comparison mask */
__u64 mask;
-
- /** @timeout: how long to wait before bailing, value in jiffies */
+ /**
+ * @timeout: how long to wait before bailing, value in nanoseconds.
+ * Without DRM_XE_UFENCE_WAIT_ABSTIME flag set (relative timeout)
+ * it contains timeout expressed in nanoseconds to wait (fence will
+ * expire at now() + timeout).
+ * When DRM_XE_UFENCE_WAIT_ABSTIME flat is set (absolute timeout) wait
+ * will end at timeout (uses system MONOTONIC_CLOCK).
+ * Passing negative timeout leads to neverending wait.
+ *
+ * On relative timeout this value is updated with timeout left
+ * (for restarting the call in case of signal delivery).
+ * On absolute timeout this value stays intact (restarted call still
+ * expire at the same point of time).
+ */
__s64 timeout;
/**