Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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 <drm/xe_drm.h>
 12
 13#include "xe_device.h"
 14#include "xe_gt.h"
 15#include "xe_macros.h"
 16#include "xe_exec_queue.h"
 17
 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) {
 29	case DRM_XE_UFENCE_WAIT_OP_EQ:
 30		passed = (rvalue & mask) == (value & mask);
 31		break;
 32	case DRM_XE_UFENCE_WAIT_OP_NEQ:
 33		passed = (rvalue & mask) != (value & mask);
 34		break;
 35	case DRM_XE_UFENCE_WAIT_OP_GT:
 36		passed = (rvalue & mask) > (value & mask);
 37		break;
 38	case DRM_XE_UFENCE_WAIT_OP_GTE:
 39		passed = (rvalue & mask) >= (value & mask);
 40		break;
 41	case DRM_XE_UFENCE_WAIT_OP_LT:
 42		passed = (rvalue & mask) < (value & mask);
 43		break;
 44	case DRM_XE_UFENCE_WAIT_OP_LTE:
 45		passed = (rvalue & mask) <= (value & mask);
 46		break;
 47	default:
 48		XE_WARN_ON("Not possible");
 49		return -EINVAL;
 50	}
 51
 52	return passed ? 0 : 1;
 53}
 54
 55#define VALID_FLAGS	DRM_XE_UFENCE_WAIT_FLAG_ABSTIME
 56#define MAX_OP		DRM_XE_UFENCE_WAIT_OP_LTE
 57
 58static long to_jiffies_timeout(struct xe_device *xe,
 59			       struct drm_xe_wait_user_fence *args)
 60{
 61	unsigned long long t;
 62	long timeout;
 63
 64	/*
 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	 */
 82	if (args->flags & DRM_XE_UFENCE_WAIT_FLAG_ABSTIME)
 83		t = drm_timeout_abs_to_jiffies(args->timeout);
 84	else
 85		t = nsecs_to_jiffies(args->timeout);
 86
 87	/*
 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;
 97
 98	return timeout ?: 1;
 99}
100
101int 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);
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;
110	int err = 0;
111	long timeout;
112	ktime_t start;
113
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]))
117		return -EINVAL;
118
119	if (XE_IOCTL_DBG(xe, args->flags & ~VALID_FLAGS))
120		return -EINVAL;
121
122	if (XE_IOCTL_DBG(xe, args->op > MAX_OP))
123		return -EINVAL;
124
125	if (XE_IOCTL_DBG(xe, addr & 0x7))
126		return -EINVAL;
127
128	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
134	timeout = to_jiffies_timeout(xe, args);
135
136	start = ktime_get();
137
138	add_wait_queue(&xe->ufence_wq, &w_wait);
139	for (;;) {
140		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
149		if (q) {
150			if (q->ops->reset_status(q)) {
151				drm_info(&xe->drm, "exec gueue reset detected\n");
152				err = -EIO;
153				break;
154			}
155		}
156
157		if (!timeout) {
158			err = -ETIME;
159			break;
160		}
161
162		timeout = wait_woken(&w_wait, TASK_INTERRUPTIBLE, timeout);
163	}
164	remove_wait_queue(&xe->ufence_wq, &w_wait);
165
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)
169			args->timeout = 0;
170	}
171
172	if (!timeout && !(err < 0))
173		err = -ETIME;
174
175	if (q)
176		xe_exec_queue_put(q);
177
178	return err;
179}