blob: d46fa8374980cdb8bd65e0b7555780909a8c605f [file] [log] [blame]
Matthew Brostdd08ebf2023-03-30 17:31:57 -04001// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2022 Intel Corporation
4 */
5
Lucas De Marchicb30cfd2023-02-21 15:33:48 -08006#include "xe_wait_user_fence.h"
7
Matthew Brostdd08ebf2023-03-30 17:31:57 -04008#include <drm/drm_device.h>
9#include <drm/drm_file.h>
Zbigniew Kempczyński5572a002023-06-28 07:51:41 +020010#include <drm/drm_utils.h>
Jani Nikula87d8ecf2024-08-27 12:15:39 +030011#include <uapi/drm/xe_drm.h>
Matthew Brostdd08ebf2023-03-30 17:31:57 -040012
13#include "xe_device.h"
14#include "xe_gt.h"
15#include "xe_macros.h"
Bommu Krishnaiahe670f0b2023-12-15 15:45:34 +000016#include "xe_exec_queue.h"
Matthew Brostdd08ebf2023-03-30 17:31:57 -040017
18static int do_compare(u64 addr, u64 value, u64 mask, u16 op)
19{
20 u64 rvalue;
21 int err;
22 bool passed;
23
24 err = copy_from_user(&rvalue, u64_to_user_ptr(addr), sizeof(rvalue));
25 if (err)
26 return -EFAULT;
27
28 switch (op) {
Rodrigo Vivi4a349c82023-11-14 13:34:33 +000029 case DRM_XE_UFENCE_WAIT_OP_EQ:
Matthew Brostdd08ebf2023-03-30 17:31:57 -040030 passed = (rvalue & mask) == (value & mask);
31 break;
Rodrigo Vivi4a349c82023-11-14 13:34:33 +000032 case DRM_XE_UFENCE_WAIT_OP_NEQ:
Matthew Brostdd08ebf2023-03-30 17:31:57 -040033 passed = (rvalue & mask) != (value & mask);
34 break;
Rodrigo Vivi4a349c82023-11-14 13:34:33 +000035 case DRM_XE_UFENCE_WAIT_OP_GT:
Matthew Brostdd08ebf2023-03-30 17:31:57 -040036 passed = (rvalue & mask) > (value & mask);
37 break;
Rodrigo Vivi4a349c82023-11-14 13:34:33 +000038 case DRM_XE_UFENCE_WAIT_OP_GTE:
Matthew Brostdd08ebf2023-03-30 17:31:57 -040039 passed = (rvalue & mask) >= (value & mask);
40 break;
Rodrigo Vivi4a349c82023-11-14 13:34:33 +000041 case DRM_XE_UFENCE_WAIT_OP_LT:
Matthew Brostdd08ebf2023-03-30 17:31:57 -040042 passed = (rvalue & mask) < (value & mask);
43 break;
Rodrigo Vivi4a349c82023-11-14 13:34:33 +000044 case DRM_XE_UFENCE_WAIT_OP_LTE:
Matthew Brostdd08ebf2023-03-30 17:31:57 -040045 passed = (rvalue & mask) <= (value & mask);
46 break;
47 default:
Francois Dugast99fea682023-07-27 14:55:29 +000048 XE_WARN_ON("Not possible");
Lucas De Marchi717cf0a2023-12-18 08:33:01 -080049 return -EINVAL;
Matthew Brostdd08ebf2023-03-30 17:31:57 -040050 }
51
52 return passed ? 0 : 1;
53}
54
Bommu Krishnaiah9212da02023-12-15 15:45:33 +000055#define VALID_FLAGS DRM_XE_UFENCE_WAIT_FLAG_ABSTIME
Rodrigo Vivi4a349c82023-11-14 13:34:33 +000056#define MAX_OP DRM_XE_UFENCE_WAIT_OP_LTE
Matthew Brostdd08ebf2023-03-30 17:31:57 -040057
Fei Yange2e2d962023-09-21 15:05:00 -070058static long to_jiffies_timeout(struct xe_device *xe,
59 struct drm_xe_wait_user_fence *args)
Zbigniew Kempczyński5572a002023-06-28 07:51:41 +020060{
Fei Yange2e2d962023-09-21 15:05:00 -070061 unsigned long long t;
62 long timeout;
Zbigniew Kempczyński5572a002023-06-28 07:51:41 +020063
Fei Yange2e2d962023-09-21 15:05:00 -070064 /*
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).
69 */
70 if (args->timeout < 0) {
71 args->timeout = MAX_SCHEDULE_TIMEOUT;
72 return MAX_SCHEDULE_TIMEOUT;
73 }
74
75 if (args->timeout == 0)
76 return 0;
77
78 /*
79 * Save the timeout to an u64 variable because nsecs_to_jiffies
80 * might return a value that overflows s32 variable.
81 */
Francois Dugast3ac4a782023-11-14 13:34:28 +000082 if (args->flags & DRM_XE_UFENCE_WAIT_FLAG_ABSTIME)
Fei Yange2e2d962023-09-21 15:05:00 -070083 t = drm_timeout_abs_to_jiffies(args->timeout);
84 else
85 t = nsecs_to_jiffies(args->timeout);
Zbigniew Kempczyński5572a002023-06-28 07:51:41 +020086
Fei Yange2e2d962023-09-21 15:05:00 -070087 /*
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.
92 */
93 if (t > MAX_SCHEDULE_TIMEOUT)
94 timeout = MAX_SCHEDULE_TIMEOUT - 1;
95 else
96 timeout = t;
Zbigniew Kempczyński5572a002023-06-28 07:51:41 +020097
98 return timeout ?: 1;
99}
100
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400101int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data,
102 struct drm_file *file)
103{
104 struct xe_device *xe = to_xe_device(dev);
Bommu Krishnaiahe670f0b2023-12-15 15:45:34 +0000105 struct xe_file *xef = to_xe_file(file);
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400106 DEFINE_WAIT_FUNC(w_wait, woken_wake_function);
107 struct drm_xe_wait_user_fence *args = data;
Bommu Krishnaiahe670f0b2023-12-15 15:45:34 +0000108 struct xe_exec_queue *q = NULL;
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400109 u64 addr = args->addr;
Bommu Krishnaiahe670f0b2023-12-15 15:45:34 +0000110 int err = 0;
Fei Yange2e2d962023-09-21 15:05:00 -0700111 long timeout;
Zbigniew Kempczyński5572a002023-06-28 07:51:41 +0200112 ktime_t start;
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400113
Francois Dugastb8c1ba82023-07-17 10:20:18 +0200114 if (XE_IOCTL_DBG(xe, args->extensions) || XE_IOCTL_DBG(xe, args->pad) ||
Bommu Krishnaiah9212da02023-12-15 15:45:33 +0000115 XE_IOCTL_DBG(xe, args->pad2) ||
Francois Dugastb8c1ba82023-07-17 10:20:18 +0200116 XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1]))
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400117 return -EINVAL;
118
Francois Dugastb8c1ba82023-07-17 10:20:18 +0200119 if (XE_IOCTL_DBG(xe, args->flags & ~VALID_FLAGS))
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400120 return -EINVAL;
121
Francois Dugastb8c1ba82023-07-17 10:20:18 +0200122 if (XE_IOCTL_DBG(xe, args->op > MAX_OP))
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400123 return -EINVAL;
124
Matthew Brostb21ae512023-09-14 13:40:49 -0700125 if (XE_IOCTL_DBG(xe, addr & 0x7))
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400126 return -EINVAL;
127
Bommu Krishnaiahe670f0b2023-12-15 15:45:34 +0000128 if (args->exec_queue_id) {
129 q = xe_exec_queue_lookup(xef, args->exec_queue_id);
130 if (XE_IOCTL_DBG(xe, !q))
131 return -ENOENT;
132 }
133
Fei Yange2e2d962023-09-21 15:05:00 -0700134 timeout = to_jiffies_timeout(xe, args);
Zbigniew Kempczyński5572a002023-06-28 07:51:41 +0200135
136 start = ktime_get();
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400137
Matthew Brostb21ae512023-09-14 13:40:49 -0700138 add_wait_queue(&xe->ufence_wq, &w_wait);
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400139 for (;;) {
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400140 err = do_compare(addr, args->value, args->mask, args->op);
141 if (err <= 0)
142 break;
143
144 if (signal_pending(current)) {
145 err = -ERESTARTSYS;
146 break;
147 }
148
Bommu Krishnaiahe670f0b2023-12-15 15:45:34 +0000149 if (q) {
150 if (q->ops->reset_status(q)) {
Colin Ian King264ed172024-01-02 09:20:14 +0000151 drm_info(&xe->drm, "exec queue reset detected\n");
Bommu Krishnaiahe670f0b2023-12-15 15:45:34 +0000152 err = -EIO;
153 break;
154 }
155 }
156
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400157 if (!timeout) {
158 err = -ETIME;
159 break;
160 }
161
162 timeout = wait_woken(&w_wait, TASK_INTERRUPTIBLE, timeout);
163 }
Matthew Brostb21ae512023-09-14 13:40:49 -0700164 remove_wait_queue(&xe->ufence_wq, &w_wait);
Zbigniew Kempczyński5572a002023-06-28 07:51:41 +0200165
Francois Dugast3ac4a782023-11-14 13:34:28 +0000166 if (!(args->flags & DRM_XE_UFENCE_WAIT_FLAG_ABSTIME)) {
Zbigniew Kempczyński5572a002023-06-28 07:51:41 +0200167 args->timeout -= ktime_to_ns(ktime_sub(ktime_get(), start));
168 if (args->timeout < 0)
169 args->timeout = 0;
170 }
171
Bommu Krishnaiahe670f0b2023-12-15 15:45:34 +0000172 if (!timeout && !(err < 0))
173 err = -ETIME;
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400174
Bommu Krishnaiahe670f0b2023-12-15 15:45:34 +0000175 if (q)
176 xe_exec_queue_put(q);
177
178 return err;
Matthew Brostdd08ebf2023-03-30 17:31:57 -0400179}