1 // SPDX-License-Identifier: MIT
3 * Copyright © 2022 Intel Corporation
6 #include "xe_wait_user_fence.h"
8 #include <drm/drm_device.h>
9 #include <drm/drm_file.h>
10 #include <drm/drm_utils.h>
11 #include <drm/xe_drm.h>
13 #include "xe_device.h"
15 #include "xe_macros.h"
16 #include "xe_exec_queue.h"
18 static int do_compare(u64 addr, u64 value, u64 mask, u16 op)
24 err = copy_from_user(&rvalue, u64_to_user_ptr(addr), sizeof(rvalue));
29 case DRM_XE_UFENCE_WAIT_OP_EQ:
30 passed = (rvalue & mask) == (value & mask);
32 case DRM_XE_UFENCE_WAIT_OP_NEQ:
33 passed = (rvalue & mask) != (value & mask);
35 case DRM_XE_UFENCE_WAIT_OP_GT:
36 passed = (rvalue & mask) > (value & mask);
38 case DRM_XE_UFENCE_WAIT_OP_GTE:
39 passed = (rvalue & mask) >= (value & mask);
41 case DRM_XE_UFENCE_WAIT_OP_LT:
42 passed = (rvalue & mask) < (value & mask);
44 case DRM_XE_UFENCE_WAIT_OP_LTE:
45 passed = (rvalue & mask) <= (value & mask);
48 XE_WARN_ON("Not possible");
52 return passed ? 0 : 1;
55 #define VALID_FLAGS DRM_XE_UFENCE_WAIT_FLAG_ABSTIME
56 #define MAX_OP DRM_XE_UFENCE_WAIT_OP_LTE
58 static long to_jiffies_timeout(struct xe_device *xe,
59 struct drm_xe_wait_user_fence *args)
65 * For negative timeout we want to wait "forever" by setting
66 * MAX_SCHEDULE_TIMEOUT. But we have to assign this value also
67 * to args->timeout to avoid being zeroed on the signal delivery
68 * (see arithmetics after wait).
70 if (args->timeout < 0) {
71 args->timeout = MAX_SCHEDULE_TIMEOUT;
72 return MAX_SCHEDULE_TIMEOUT;
75 if (args->timeout == 0)
79 * Save the timeout to an u64 variable because nsecs_to_jiffies
80 * might return a value that overflows s32 variable.
82 if (args->flags & DRM_XE_UFENCE_WAIT_FLAG_ABSTIME)
83 t = drm_timeout_abs_to_jiffies(args->timeout);
85 t = nsecs_to_jiffies(args->timeout);
88 * Anything greater then MAX_SCHEDULE_TIMEOUT is meaningless,
89 * also we don't want to cap it at MAX_SCHEDULE_TIMEOUT because
90 * apparently user doesn't mean to wait forever, otherwise the
91 * args->timeout should have been set to a negative value.
93 if (t > MAX_SCHEDULE_TIMEOUT)
94 timeout = MAX_SCHEDULE_TIMEOUT - 1;
101 int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data,
102 struct drm_file *file)
104 struct xe_device *xe = to_xe_device(dev);
105 struct xe_file *xef = to_xe_file(file);
106 DEFINE_WAIT_FUNC(w_wait, woken_wake_function);
107 struct drm_xe_wait_user_fence *args = data;
108 struct xe_exec_queue *q = NULL;
109 u64 addr = args->addr;
114 if (XE_IOCTL_DBG(xe, args->extensions) || XE_IOCTL_DBG(xe, args->pad) ||
115 XE_IOCTL_DBG(xe, args->pad2) ||
116 XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1]))
119 if (XE_IOCTL_DBG(xe, args->flags & ~VALID_FLAGS))
122 if (XE_IOCTL_DBG(xe, args->op > MAX_OP))
125 if (XE_IOCTL_DBG(xe, addr & 0x7))
128 if (args->exec_queue_id) {
129 q = xe_exec_queue_lookup(xef, args->exec_queue_id);
130 if (XE_IOCTL_DBG(xe, !q))
134 timeout = to_jiffies_timeout(xe, args);
138 add_wait_queue(&xe->ufence_wq, &w_wait);
140 err = do_compare(addr, args->value, args->mask, args->op);
144 if (signal_pending(current)) {
150 if (q->ops->reset_status(q)) {
151 drm_info(&xe->drm, "exec gueue reset detected\n");
162 timeout = wait_woken(&w_wait, TASK_INTERRUPTIBLE, timeout);
164 remove_wait_queue(&xe->ufence_wq, &w_wait);
166 if (!(args->flags & DRM_XE_UFENCE_WAIT_FLAG_ABSTIME)) {
167 args->timeout -= ktime_to_ns(ktime_sub(ktime_get(), start));
168 if (args->timeout < 0)
172 if (!timeout && !(err < 0))
176 xe_exec_queue_put(q);