Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe: Use nanoseconds instead of jiffies in uapi for user fence

Using jiffies as a timeout from userspace is weird even if
theoretically exists possiblity of acquiring jiffies via getconf.
Unfortunately this method is unreliable and the returned
value may vary from the one configured in the kernel config.

Now timeout is expressed in nanoseconds and its interpretation depends
on setting DRM_XE_UFENCE_WAIT_ABSTIME flag. Relative timeout (flag
is not set) means fence expire at now() + timeout. Absolute timeout
(flag is set) means that the fence expires at exact point of time.
Passing negative timeout means we will wait "forever" by setting
wait time to MAX_SCHEDULE_TIMEOUT.

Cc: Andi Shyti <andi.shyti@linux.intel.com>
Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
Link: https://lore.kernel.org/r/20230628055141.398036-2-zbigniew.kempczynski@intel.com
Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

authored by

Zbigniew Kempczyński and committed by
Rodrigo Vivi
5572a004 2e60442a

+51 -12
+37 -10
drivers/gpu/drm/xe/xe_wait_user_fence.c
··· 7 7 8 8 #include <drm/drm_device.h> 9 9 #include <drm/drm_file.h> 10 + #include <drm/drm_utils.h> 10 11 #include <drm/xe_drm.h> 11 12 12 13 #include "xe_device.h" ··· 85 84 DRM_XE_UFENCE_WAIT_VM_ERROR) 86 85 #define MAX_OP DRM_XE_UFENCE_WAIT_LTE 87 86 87 + static unsigned long to_jiffies_timeout(struct drm_xe_wait_user_fence *args) 88 + { 89 + unsigned long timeout; 90 + 91 + if (args->flags & DRM_XE_UFENCE_WAIT_ABSTIME) 92 + return drm_timeout_abs_to_jiffies(args->timeout); 93 + 94 + if (args->timeout == MAX_SCHEDULE_TIMEOUT || args->timeout == 0) 95 + return args->timeout; 96 + 97 + timeout = nsecs_to_jiffies(args->timeout); 98 + 99 + return timeout ?: 1; 100 + } 101 + 88 102 int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data, 89 103 struct drm_file *file) 90 104 { ··· 114 98 int err; 115 99 bool no_engines = args->flags & DRM_XE_UFENCE_WAIT_SOFT_OP || 116 100 args->flags & DRM_XE_UFENCE_WAIT_VM_ERROR; 117 - unsigned long timeout = args->timeout; 101 + unsigned long timeout; 102 + ktime_t start; 118 103 119 104 if (XE_IOCTL_ERR(xe, args->extensions) || XE_IOCTL_ERR(xe, args->pad) || 120 105 XE_IOCTL_ERR(xe, args->reserved[0] || args->reserved[1])) ··· 169 152 addr = vm->async_ops.error_capture.addr; 170 153 } 171 154 172 - if (XE_IOCTL_ERR(xe, timeout > MAX_SCHEDULE_TIMEOUT)) 173 - return -EINVAL; 155 + /* 156 + * For negative timeout we want to wait "forever" by setting 157 + * MAX_SCHEDULE_TIMEOUT. But we have to assign this value also 158 + * to args->timeout to avoid being zeroed on the signal delivery 159 + * (see arithmetics after wait). 160 + */ 161 + if (args->timeout < 0) 162 + args->timeout = MAX_SCHEDULE_TIMEOUT; 163 + 164 + timeout = to_jiffies_timeout(args); 165 + 166 + start = ktime_get(); 174 167 175 168 /* 176 169 * FIXME: Very simple implementation at the moment, single wait queue ··· 219 192 } else { 220 193 remove_wait_queue(&xe->ufence_wq, &w_wait); 221 194 } 195 + 196 + if (!(args->flags & DRM_XE_UFENCE_WAIT_ABSTIME)) { 197 + args->timeout -= ktime_to_ns(ktime_sub(ktime_get(), start)); 198 + if (args->timeout < 0) 199 + args->timeout = 0; 200 + } 201 + 222 202 if (XE_IOCTL_ERR(xe, err < 0)) 223 203 return err; 224 204 else if (XE_IOCTL_ERR(xe, !timeout)) 225 205 return -ETIME; 226 - 227 - /* 228 - * Again very simple, return the time in jiffies that has past, may need 229 - * a more precision 230 - */ 231 - if (args->flags & DRM_XE_UFENCE_WAIT_ABSTIME) 232 - args->timeout = args->timeout - timeout; 233 206 234 207 return 0; 235 208 }
+14 -2
include/uapi/drm/xe_drm.h
··· 904 904 #define DRM_XE_UFENCE_WAIT_U64 0xffffffffffffffffu 905 905 /** @mask: comparison mask */ 906 906 __u64 mask; 907 - 908 - /** @timeout: how long to wait before bailing, value in jiffies */ 907 + /** 908 + * @timeout: how long to wait before bailing, value in nanoseconds. 909 + * Without DRM_XE_UFENCE_WAIT_ABSTIME flag set (relative timeout) 910 + * it contains timeout expressed in nanoseconds to wait (fence will 911 + * expire at now() + timeout). 912 + * When DRM_XE_UFENCE_WAIT_ABSTIME flat is set (absolute timeout) wait 913 + * will end at timeout (uses system MONOTONIC_CLOCK). 914 + * Passing negative timeout leads to neverending wait. 915 + * 916 + * On relative timeout this value is updated with timeout left 917 + * (for restarting the call in case of signal delivery). 918 + * On absolute timeout this value stays intact (restarted call still 919 + * expire at the same point of time). 920 + */ 909 921 __s64 timeout; 910 922 911 923 /**