1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2022 Intel Corporation 4 */ 5 6 #include "xe_wait_user_fence.h" 7 8 #include <drm/drm_device.h> 9 #include <drm/drm_file.h> 10 #include <drm/drm_utils.h> 11 #include <uapi/drm/xe_drm.h> 12 13 #include "xe_device.h" 14 #include "xe_macros.h" 15 #include "xe_exec_queue.h" 16 17 static int do_compare(u64 addr, u64 value, u64 mask, u16 op) 18 { 19 u64 rvalue; 20 int err; 21 bool passed; 22 23 err = copy_from_user(&rvalue, u64_to_user_ptr(addr), sizeof(rvalue)); 24 if (err) 25 return -EFAULT; 26 27 switch (op) { 28 case DRM_XE_UFENCE_WAIT_OP_EQ: 29 passed = (rvalue & mask) == (value & mask); 30 break; 31 case DRM_XE_UFENCE_WAIT_OP_NEQ: 32 passed = (rvalue & mask) != (value & mask); 33 break; 34 case DRM_XE_UFENCE_WAIT_OP_GT: 35 passed = (rvalue & mask) > (value & mask); 36 break; 37 case DRM_XE_UFENCE_WAIT_OP_GTE: 38 passed = (rvalue & mask) >= (value & mask); 39 break; 40 case DRM_XE_UFENCE_WAIT_OP_LT: 41 passed = (rvalue & mask) < (value & mask); 42 break; 43 case DRM_XE_UFENCE_WAIT_OP_LTE: 44 passed = (rvalue & mask) <= (value & mask); 45 break; 46 default: 47 XE_WARN_ON("Not possible"); 48 return -EINVAL; 49 } 50 51 return passed ? 0 : 1; 52 } 53 54 #define VALID_FLAGS DRM_XE_UFENCE_WAIT_FLAG_ABSTIME 55 #define MAX_OP DRM_XE_UFENCE_WAIT_OP_LTE 56 57 static long to_jiffies_timeout(struct xe_device *xe, 58 struct drm_xe_wait_user_fence *args) 59 { 60 unsigned long long t; 61 long timeout; 62 63 /* 64 * For negative timeout we want to wait "forever" by setting 65 * MAX_SCHEDULE_TIMEOUT. But we have to assign this value also 66 * to args->timeout to avoid being zeroed on the signal delivery 67 * (see arithmetics after wait). 68 */ 69 if (args->timeout < 0) { 70 args->timeout = MAX_SCHEDULE_TIMEOUT; 71 return MAX_SCHEDULE_TIMEOUT; 72 } 73 74 if (args->timeout == 0) 75 return 0; 76 77 /* 78 * Save the timeout to an u64 variable because nsecs_to_jiffies 79 * might return a value that overflows s32 variable. 80 */ 81 if (args->flags & DRM_XE_UFENCE_WAIT_FLAG_ABSTIME) 82 t = drm_timeout_abs_to_jiffies(args->timeout); 83 else 84 t = nsecs_to_jiffies(args->timeout); 85 86 /* 87 * Anything greater then MAX_SCHEDULE_TIMEOUT is meaningless, 88 * also we don't want to cap it at MAX_SCHEDULE_TIMEOUT because 89 * apparently user doesn't mean to wait forever, otherwise the 90 * args->timeout should have been set to a negative value. 91 */ 92 if (t > MAX_SCHEDULE_TIMEOUT) 93 timeout = MAX_SCHEDULE_TIMEOUT - 1; 94 else 95 timeout = t; 96 97 return timeout ?: 1; 98 } 99 100 int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data, 101 struct drm_file *file) 102 { 103 struct xe_device *xe = to_xe_device(dev); 104 struct xe_file *xef = to_xe_file(file); 105 DEFINE_WAIT_FUNC(w_wait, woken_wake_function); 106 struct drm_xe_wait_user_fence *args = data; 107 struct xe_exec_queue *q = NULL; 108 u64 addr = args->addr; 109 int err = 0; 110 long timeout; 111 ktime_t start; 112 113 if (XE_IOCTL_DBG(xe, args->extensions) || XE_IOCTL_DBG(xe, args->pad) || 114 XE_IOCTL_DBG(xe, args->pad2) || 115 XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1])) 116 return -EINVAL; 117 118 if (XE_IOCTL_DBG(xe, args->flags & ~VALID_FLAGS)) 119 return -EINVAL; 120 121 if (XE_IOCTL_DBG(xe, args->op > MAX_OP)) 122 return -EINVAL; 123 124 if (XE_IOCTL_DBG(xe, addr & 0x7)) 125 return -EINVAL; 126 127 if (args->exec_queue_id) { 128 q = xe_exec_queue_lookup(xef, args->exec_queue_id); 129 if (XE_IOCTL_DBG(xe, !q)) 130 return -ENOENT; 131 } 132 133 timeout = to_jiffies_timeout(xe, args); 134 135 start = ktime_get(); 136 137 add_wait_queue(&xe->ufence_wq, &w_wait); 138 for (;;) { 139 err = do_compare(addr, args->value, args->mask, args->op); 140 if (err <= 0) 141 break; 142 143 if (signal_pending(current)) { 144 err = -ERESTARTSYS; 145 break; 146 } 147 148 if (q) { 149 if (q->ops->reset_status(q)) { 150 drm_info(&xe->drm, "exec queue reset detected\n"); 151 err = -EIO; 152 break; 153 } 154 } 155 156 if (!timeout) { 157 LNL_FLUSH_WORKQUEUE(xe->ordered_wq); 158 err = do_compare(addr, args->value, args->mask, 159 args->op); 160 if (err <= 0) { 161 drm_dbg(&xe->drm, "LNL_FLUSH_WORKQUEUE resolved ufence timeout\n"); 162 break; 163 } 164 err = -ETIME; 165 break; 166 } 167 168 timeout = wait_woken(&w_wait, TASK_INTERRUPTIBLE, timeout); 169 } 170 remove_wait_queue(&xe->ufence_wq, &w_wait); 171 172 if (!(args->flags & DRM_XE_UFENCE_WAIT_FLAG_ABSTIME)) { 173 args->timeout -= ktime_to_ns(ktime_sub(ktime_get(), start)); 174 if (args->timeout < 0) 175 args->timeout = 0; 176 } 177 178 if (q) 179 xe_exec_queue_put(q); 180 181 return err; 182 } 183