xref: /openbmc/linux/drivers/gpu/drm/tegra/uapi.c (revision 8935002f)
1d7c591bcSMikko Perttunen // SPDX-License-Identifier: GPL-2.0-only
2d7c591bcSMikko Perttunen /* Copyright (c) 2020 NVIDIA Corporation */
3d7c591bcSMikko Perttunen 
4d7c591bcSMikko Perttunen #include <linux/host1x.h>
5d7c591bcSMikko Perttunen #include <linux/iommu.h>
6d7c591bcSMikko Perttunen #include <linux/list.h>
7d7c591bcSMikko Perttunen 
8d7c591bcSMikko Perttunen #include <drm/drm_drv.h>
9d7c591bcSMikko Perttunen #include <drm/drm_file.h>
1044e96138SMikko Perttunen #include <drm/drm_utils.h>
11d7c591bcSMikko Perttunen 
12d7c591bcSMikko Perttunen #include "drm.h"
13d7c591bcSMikko Perttunen #include "uapi.h"
14d7c591bcSMikko Perttunen 
tegra_drm_mapping_release(struct kref * ref)15d7c591bcSMikko Perttunen static void tegra_drm_mapping_release(struct kref *ref)
16d7c591bcSMikko Perttunen {
17d7c591bcSMikko Perttunen 	struct tegra_drm_mapping *mapping =
18d7c591bcSMikko Perttunen 		container_of(ref, struct tegra_drm_mapping, ref);
19d7c591bcSMikko Perttunen 
20c6aeaf56SThierry Reding 	host1x_bo_unpin(mapping->map);
21d7c591bcSMikko Perttunen 	host1x_bo_put(mapping->bo);
22d7c591bcSMikko Perttunen 
23d7c591bcSMikko Perttunen 	kfree(mapping);
24d7c591bcSMikko Perttunen }
25d7c591bcSMikko Perttunen 
tegra_drm_mapping_put(struct tegra_drm_mapping * mapping)26d7c591bcSMikko Perttunen void tegra_drm_mapping_put(struct tegra_drm_mapping *mapping)
27d7c591bcSMikko Perttunen {
28d7c591bcSMikko Perttunen 	kref_put(&mapping->ref, tegra_drm_mapping_release);
29d7c591bcSMikko Perttunen }
30d7c591bcSMikko Perttunen 
tegra_drm_channel_context_close(struct tegra_drm_context * context)31d7c591bcSMikko Perttunen static void tegra_drm_channel_context_close(struct tegra_drm_context *context)
32d7c591bcSMikko Perttunen {
33d7c591bcSMikko Perttunen 	struct tegra_drm_mapping *mapping;
34d7c591bcSMikko Perttunen 	unsigned long id;
35d7c591bcSMikko Perttunen 
36e09db978SMikko Perttunen 	if (context->memory_context)
37e09db978SMikko Perttunen 		host1x_memory_context_put(context->memory_context);
38e09db978SMikko Perttunen 
39d7c591bcSMikko Perttunen 	xa_for_each(&context->mappings, id, mapping)
40d7c591bcSMikko Perttunen 		tegra_drm_mapping_put(mapping);
41d7c591bcSMikko Perttunen 
42d7c591bcSMikko Perttunen 	xa_destroy(&context->mappings);
43d7c591bcSMikko Perttunen 
44d7c591bcSMikko Perttunen 	host1x_channel_put(context->channel);
45d7c591bcSMikko Perttunen 
46d7c591bcSMikko Perttunen 	kfree(context);
47d7c591bcSMikko Perttunen }
48d7c591bcSMikko Perttunen 
tegra_drm_uapi_close_file(struct tegra_drm_file * file)49d7c591bcSMikko Perttunen void tegra_drm_uapi_close_file(struct tegra_drm_file *file)
50d7c591bcSMikko Perttunen {
51d7c591bcSMikko Perttunen 	struct tegra_drm_context *context;
52fc348336SMikko Perttunen 	struct host1x_syncpt *sp;
53d7c591bcSMikko Perttunen 	unsigned long id;
54d7c591bcSMikko Perttunen 
55d7c591bcSMikko Perttunen 	xa_for_each(&file->contexts, id, context)
56d7c591bcSMikko Perttunen 		tegra_drm_channel_context_close(context);
57d7c591bcSMikko Perttunen 
58fc348336SMikko Perttunen 	xa_for_each(&file->syncpoints, id, sp)
59fc348336SMikko Perttunen 		host1x_syncpt_put(sp);
60fc348336SMikko Perttunen 
61d7c591bcSMikko Perttunen 	xa_destroy(&file->contexts);
62fc348336SMikko Perttunen 	xa_destroy(&file->syncpoints);
63d7c591bcSMikko Perttunen }
64d7c591bcSMikko Perttunen 
tegra_drm_find_client(struct tegra_drm * tegra,u32 class)65d7c591bcSMikko Perttunen static struct tegra_drm_client *tegra_drm_find_client(struct tegra_drm *tegra, u32 class)
66d7c591bcSMikko Perttunen {
67d7c591bcSMikko Perttunen 	struct tegra_drm_client *client;
68d7c591bcSMikko Perttunen 
69d7c591bcSMikko Perttunen 	list_for_each_entry(client, &tegra->clients, list)
70d7c591bcSMikko Perttunen 		if (client->base.class == class)
71d7c591bcSMikko Perttunen 			return client;
72d7c591bcSMikko Perttunen 
73d7c591bcSMikko Perttunen 	return NULL;
74d7c591bcSMikko Perttunen }
75d7c591bcSMikko Perttunen 
tegra_drm_ioctl_channel_open(struct drm_device * drm,void * data,struct drm_file * file)76d7c591bcSMikko Perttunen int tegra_drm_ioctl_channel_open(struct drm_device *drm, void *data, struct drm_file *file)
77d7c591bcSMikko Perttunen {
78e09db978SMikko Perttunen 	struct host1x *host = tegra_drm_to_host1x(drm->dev_private);
79d7c591bcSMikko Perttunen 	struct tegra_drm_file *fpriv = file->driver_priv;
80d7c591bcSMikko Perttunen 	struct tegra_drm *tegra = drm->dev_private;
81d7c591bcSMikko Perttunen 	struct drm_tegra_channel_open *args = data;
82d7c591bcSMikko Perttunen 	struct tegra_drm_client *client = NULL;
83d7c591bcSMikko Perttunen 	struct tegra_drm_context *context;
84d7c591bcSMikko Perttunen 	int err;
85d7c591bcSMikko Perttunen 
86d7c591bcSMikko Perttunen 	if (args->flags)
87d7c591bcSMikko Perttunen 		return -EINVAL;
88d7c591bcSMikko Perttunen 
89d7c591bcSMikko Perttunen 	context = kzalloc(sizeof(*context), GFP_KERNEL);
90d7c591bcSMikko Perttunen 	if (!context)
91d7c591bcSMikko Perttunen 		return -ENOMEM;
92d7c591bcSMikko Perttunen 
93d7c591bcSMikko Perttunen 	client = tegra_drm_find_client(tegra, args->host1x_class);
94d7c591bcSMikko Perttunen 	if (!client) {
95d7c591bcSMikko Perttunen 		err = -ENODEV;
96d7c591bcSMikko Perttunen 		goto free;
97d7c591bcSMikko Perttunen 	}
98d7c591bcSMikko Perttunen 
99d7c591bcSMikko Perttunen 	if (client->shared_channel) {
100d7c591bcSMikko Perttunen 		context->channel = host1x_channel_get(client->shared_channel);
101d7c591bcSMikko Perttunen 	} else {
102d7c591bcSMikko Perttunen 		context->channel = host1x_channel_request(&client->base);
103d7c591bcSMikko Perttunen 		if (!context->channel) {
104d7c591bcSMikko Perttunen 			err = -EBUSY;
105d7c591bcSMikko Perttunen 			goto free;
106d7c591bcSMikko Perttunen 		}
107d7c591bcSMikko Perttunen 	}
108d7c591bcSMikko Perttunen 
109e09db978SMikko Perttunen 	/* Only allocate context if the engine supports context isolation. */
110e09db978SMikko Perttunen 	if (device_iommu_mapped(client->base.dev) && client->ops->can_use_memory_ctx) {
111e09db978SMikko Perttunen 		bool supported;
112e09db978SMikko Perttunen 
113e09db978SMikko Perttunen 		err = client->ops->can_use_memory_ctx(client, &supported);
114e09db978SMikko Perttunen 		if (err)
115e09db978SMikko Perttunen 			goto put_channel;
116e09db978SMikko Perttunen 
117e09db978SMikko Perttunen 		if (supported)
118e09db978SMikko Perttunen 			context->memory_context = host1x_memory_context_alloc(
119*8935002fSMikko Perttunen 				host, client->base.dev, get_task_pid(current, PIDTYPE_TGID));
120e09db978SMikko Perttunen 
121e09db978SMikko Perttunen 		if (IS_ERR(context->memory_context)) {
122e09db978SMikko Perttunen 			if (PTR_ERR(context->memory_context) != -EOPNOTSUPP) {
123e09db978SMikko Perttunen 				err = PTR_ERR(context->memory_context);
124e09db978SMikko Perttunen 				goto put_channel;
125e09db978SMikko Perttunen 			} else {
126e09db978SMikko Perttunen 				/*
127e09db978SMikko Perttunen 				 * OK, HW does not support contexts or contexts
128e09db978SMikko Perttunen 				 * are disabled.
129e09db978SMikko Perttunen 				 */
130e09db978SMikko Perttunen 				context->memory_context = NULL;
131e09db978SMikko Perttunen 			}
132e09db978SMikko Perttunen 		}
133e09db978SMikko Perttunen 	}
134e09db978SMikko Perttunen 
135d7c591bcSMikko Perttunen 	err = xa_alloc(&fpriv->contexts, &args->context, context, XA_LIMIT(1, U32_MAX),
136d7c591bcSMikko Perttunen 		       GFP_KERNEL);
137d7c591bcSMikko Perttunen 	if (err < 0)
138e09db978SMikko Perttunen 		goto put_memctx;
139d7c591bcSMikko Perttunen 
140d7c591bcSMikko Perttunen 	context->client = client;
141d7c591bcSMikko Perttunen 	xa_init_flags(&context->mappings, XA_FLAGS_ALLOC1);
142d7c591bcSMikko Perttunen 
143d7c591bcSMikko Perttunen 	args->version = client->version;
144d7c591bcSMikko Perttunen 	args->capabilities = 0;
145d7c591bcSMikko Perttunen 
146d7c591bcSMikko Perttunen 	if (device_get_dma_attr(client->base.dev) == DEV_DMA_COHERENT)
147d7c591bcSMikko Perttunen 		args->capabilities |= DRM_TEGRA_CHANNEL_CAP_CACHE_COHERENT;
148d7c591bcSMikko Perttunen 
149d7c591bcSMikko Perttunen 	return 0;
150d7c591bcSMikko Perttunen 
151e09db978SMikko Perttunen put_memctx:
152e09db978SMikko Perttunen 	if (context->memory_context)
153e09db978SMikko Perttunen 		host1x_memory_context_put(context->memory_context);
154d7c591bcSMikko Perttunen put_channel:
155d7c591bcSMikko Perttunen 	host1x_channel_put(context->channel);
156d7c591bcSMikko Perttunen free:
157d7c591bcSMikko Perttunen 	kfree(context);
158d7c591bcSMikko Perttunen 
159d7c591bcSMikko Perttunen 	return err;
160d7c591bcSMikko Perttunen }
161d7c591bcSMikko Perttunen 
tegra_drm_ioctl_channel_close(struct drm_device * drm,void * data,struct drm_file * file)162d7c591bcSMikko Perttunen int tegra_drm_ioctl_channel_close(struct drm_device *drm, void *data, struct drm_file *file)
163d7c591bcSMikko Perttunen {
164d7c591bcSMikko Perttunen 	struct tegra_drm_file *fpriv = file->driver_priv;
165d7c591bcSMikko Perttunen 	struct drm_tegra_channel_close *args = data;
166d7c591bcSMikko Perttunen 	struct tegra_drm_context *context;
167d7c591bcSMikko Perttunen 
168d7c591bcSMikko Perttunen 	mutex_lock(&fpriv->lock);
169d7c591bcSMikko Perttunen 
170d7c591bcSMikko Perttunen 	context = xa_load(&fpriv->contexts, args->context);
171d7c591bcSMikko Perttunen 	if (!context) {
172d7c591bcSMikko Perttunen 		mutex_unlock(&fpriv->lock);
173d7c591bcSMikko Perttunen 		return -EINVAL;
174d7c591bcSMikko Perttunen 	}
175d7c591bcSMikko Perttunen 
176d7c591bcSMikko Perttunen 	xa_erase(&fpriv->contexts, args->context);
177d7c591bcSMikko Perttunen 
178d7c591bcSMikko Perttunen 	mutex_unlock(&fpriv->lock);
179d7c591bcSMikko Perttunen 
180d7c591bcSMikko Perttunen 	tegra_drm_channel_context_close(context);
181d7c591bcSMikko Perttunen 
182d7c591bcSMikko Perttunen 	return 0;
183d7c591bcSMikko Perttunen }
184d7c591bcSMikko Perttunen 
tegra_drm_ioctl_channel_map(struct drm_device * drm,void * data,struct drm_file * file)185d7c591bcSMikko Perttunen int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data, struct drm_file *file)
186d7c591bcSMikko Perttunen {
187d7c591bcSMikko Perttunen 	struct tegra_drm_file *fpriv = file->driver_priv;
188d7c591bcSMikko Perttunen 	struct drm_tegra_channel_map *args = data;
189d7c591bcSMikko Perttunen 	struct tegra_drm_mapping *mapping;
190d7c591bcSMikko Perttunen 	struct tegra_drm_context *context;
191c6aeaf56SThierry Reding 	enum dma_data_direction direction;
192e09db978SMikko Perttunen 	struct device *mapping_dev;
193d7c591bcSMikko Perttunen 	int err = 0;
194d7c591bcSMikko Perttunen 
195d7c591bcSMikko Perttunen 	if (args->flags & ~DRM_TEGRA_CHANNEL_MAP_READ_WRITE)
196d7c591bcSMikko Perttunen 		return -EINVAL;
197d7c591bcSMikko Perttunen 
198d7c591bcSMikko Perttunen 	mutex_lock(&fpriv->lock);
199d7c591bcSMikko Perttunen 
200d7c591bcSMikko Perttunen 	context = xa_load(&fpriv->contexts, args->context);
201d7c591bcSMikko Perttunen 	if (!context) {
202d7c591bcSMikko Perttunen 		mutex_unlock(&fpriv->lock);
203d7c591bcSMikko Perttunen 		return -EINVAL;
204d7c591bcSMikko Perttunen 	}
205d7c591bcSMikko Perttunen 
206d7c591bcSMikko Perttunen 	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
207d7c591bcSMikko Perttunen 	if (!mapping) {
208d7c591bcSMikko Perttunen 		err = -ENOMEM;
209d7c591bcSMikko Perttunen 		goto unlock;
210d7c591bcSMikko Perttunen 	}
211d7c591bcSMikko Perttunen 
212d7c591bcSMikko Perttunen 	kref_init(&mapping->ref);
213d7c591bcSMikko Perttunen 
214e09db978SMikko Perttunen 	if (context->memory_context)
215e09db978SMikko Perttunen 		mapping_dev = &context->memory_context->dev;
216e09db978SMikko Perttunen 	else
217e09db978SMikko Perttunen 		mapping_dev = context->client->base.dev;
218e09db978SMikko Perttunen 
219d7c591bcSMikko Perttunen 	mapping->bo = tegra_gem_lookup(file, args->handle);
220d7c591bcSMikko Perttunen 	if (!mapping->bo) {
221d7c591bcSMikko Perttunen 		err = -EINVAL;
222c6aeaf56SThierry Reding 		goto free;
223d7c591bcSMikko Perttunen 	}
224d7c591bcSMikko Perttunen 
225d7c591bcSMikko Perttunen 	switch (args->flags & DRM_TEGRA_CHANNEL_MAP_READ_WRITE) {
226d7c591bcSMikko Perttunen 	case DRM_TEGRA_CHANNEL_MAP_READ_WRITE:
227c6aeaf56SThierry Reding 		direction = DMA_BIDIRECTIONAL;
228d7c591bcSMikko Perttunen 		break;
229d7c591bcSMikko Perttunen 
230d7c591bcSMikko Perttunen 	case DRM_TEGRA_CHANNEL_MAP_WRITE:
231c6aeaf56SThierry Reding 		direction = DMA_FROM_DEVICE;
232d7c591bcSMikko Perttunen 		break;
233d7c591bcSMikko Perttunen 
234d7c591bcSMikko Perttunen 	case DRM_TEGRA_CHANNEL_MAP_READ:
235c6aeaf56SThierry Reding 		direction = DMA_TO_DEVICE;
236d7c591bcSMikko Perttunen 		break;
237d7c591bcSMikko Perttunen 
238d7c591bcSMikko Perttunen 	default:
239c6aeaf56SThierry Reding 		err = -EINVAL;
240d7c591bcSMikko Perttunen 		goto put_gem;
241d7c591bcSMikko Perttunen 	}
242d7c591bcSMikko Perttunen 
243e09db978SMikko Perttunen 	mapping->map = host1x_bo_pin(mapping_dev, mapping->bo, direction, NULL);
244c6aeaf56SThierry Reding 	if (IS_ERR(mapping->map)) {
245c6aeaf56SThierry Reding 		err = PTR_ERR(mapping->map);
246c6aeaf56SThierry Reding 		goto put_gem;
247d7c591bcSMikko Perttunen 	}
248d7c591bcSMikko Perttunen 
249c6aeaf56SThierry Reding 	mapping->iova = mapping->map->phys;
2508a44924eSDmitry Osipenko 	mapping->iova_end = mapping->iova + host1x_to_tegra_bo(mapping->bo)->gem.size;
251d7c591bcSMikko Perttunen 
252d7c591bcSMikko Perttunen 	err = xa_alloc(&context->mappings, &args->mapping, mapping, XA_LIMIT(1, U32_MAX),
253d7c591bcSMikko Perttunen 		       GFP_KERNEL);
254d7c591bcSMikko Perttunen 	if (err < 0)
255c6aeaf56SThierry Reding 		goto unpin;
256d7c591bcSMikko Perttunen 
257d7c591bcSMikko Perttunen 	mutex_unlock(&fpriv->lock);
258d7c591bcSMikko Perttunen 
259d7c591bcSMikko Perttunen 	return 0;
260d7c591bcSMikko Perttunen 
261d7c591bcSMikko Perttunen unpin:
262c6aeaf56SThierry Reding 	host1x_bo_unpin(mapping->map);
263d7c591bcSMikko Perttunen put_gem:
264d7c591bcSMikko Perttunen 	host1x_bo_put(mapping->bo);
265c6aeaf56SThierry Reding free:
266d7c591bcSMikko Perttunen 	kfree(mapping);
267d7c591bcSMikko Perttunen unlock:
268d7c591bcSMikko Perttunen 	mutex_unlock(&fpriv->lock);
269d7c591bcSMikko Perttunen 	return err;
270d7c591bcSMikko Perttunen }
271d7c591bcSMikko Perttunen 
tegra_drm_ioctl_channel_unmap(struct drm_device * drm,void * data,struct drm_file * file)272d7c591bcSMikko Perttunen int tegra_drm_ioctl_channel_unmap(struct drm_device *drm, void *data, struct drm_file *file)
273d7c591bcSMikko Perttunen {
274d7c591bcSMikko Perttunen 	struct tegra_drm_file *fpriv = file->driver_priv;
275d7c591bcSMikko Perttunen 	struct drm_tegra_channel_unmap *args = data;
276d7c591bcSMikko Perttunen 	struct tegra_drm_mapping *mapping;
277d7c591bcSMikko Perttunen 	struct tegra_drm_context *context;
278d7c591bcSMikko Perttunen 
279d7c591bcSMikko Perttunen 	mutex_lock(&fpriv->lock);
280d7c591bcSMikko Perttunen 
281d7c591bcSMikko Perttunen 	context = xa_load(&fpriv->contexts, args->context);
282d7c591bcSMikko Perttunen 	if (!context) {
283d7c591bcSMikko Perttunen 		mutex_unlock(&fpriv->lock);
284d7c591bcSMikko Perttunen 		return -EINVAL;
285d7c591bcSMikko Perttunen 	}
286d7c591bcSMikko Perttunen 
287d7c591bcSMikko Perttunen 	mapping = xa_erase(&context->mappings, args->mapping);
288d7c591bcSMikko Perttunen 
289d7c591bcSMikko Perttunen 	mutex_unlock(&fpriv->lock);
290d7c591bcSMikko Perttunen 
291d7c591bcSMikko Perttunen 	if (!mapping)
292d7c591bcSMikko Perttunen 		return -EINVAL;
293d7c591bcSMikko Perttunen 
294d7c591bcSMikko Perttunen 	tegra_drm_mapping_put(mapping);
295d7c591bcSMikko Perttunen 	return 0;
296d7c591bcSMikko Perttunen }
297d7c591bcSMikko Perttunen 
tegra_drm_ioctl_syncpoint_allocate(struct drm_device * drm,void * data,struct drm_file * file)298fc348336SMikko Perttunen int tegra_drm_ioctl_syncpoint_allocate(struct drm_device *drm, void *data, struct drm_file *file)
299fc348336SMikko Perttunen {
300fc348336SMikko Perttunen 	struct host1x *host1x = tegra_drm_to_host1x(drm->dev_private);
301fc348336SMikko Perttunen 	struct tegra_drm_file *fpriv = file->driver_priv;
302fc348336SMikko Perttunen 	struct drm_tegra_syncpoint_allocate *args = data;
303fc348336SMikko Perttunen 	struct host1x_syncpt *sp;
304fc348336SMikko Perttunen 	int err;
305fc348336SMikko Perttunen 
306fc348336SMikko Perttunen 	if (args->id)
307fc348336SMikko Perttunen 		return -EINVAL;
308fc348336SMikko Perttunen 
309fc348336SMikko Perttunen 	sp = host1x_syncpt_alloc(host1x, HOST1X_SYNCPT_CLIENT_MANAGED, current->comm);
310fc348336SMikko Perttunen 	if (!sp)
311fc348336SMikko Perttunen 		return -EBUSY;
312fc348336SMikko Perttunen 
313fc348336SMikko Perttunen 	args->id = host1x_syncpt_id(sp);
314fc348336SMikko Perttunen 
315fc348336SMikko Perttunen 	err = xa_insert(&fpriv->syncpoints, args->id, sp, GFP_KERNEL);
316fc348336SMikko Perttunen 	if (err) {
317fc348336SMikko Perttunen 		host1x_syncpt_put(sp);
318fc348336SMikko Perttunen 		return err;
319fc348336SMikko Perttunen 	}
320fc348336SMikko Perttunen 
321fc348336SMikko Perttunen 	return 0;
322fc348336SMikko Perttunen }
323fc348336SMikko Perttunen 
tegra_drm_ioctl_syncpoint_free(struct drm_device * drm,void * data,struct drm_file * file)324fc348336SMikko Perttunen int tegra_drm_ioctl_syncpoint_free(struct drm_device *drm, void *data, struct drm_file *file)
325fc348336SMikko Perttunen {
326fc348336SMikko Perttunen 	struct tegra_drm_file *fpriv = file->driver_priv;
327fc348336SMikko Perttunen 	struct drm_tegra_syncpoint_allocate *args = data;
328fc348336SMikko Perttunen 	struct host1x_syncpt *sp;
329fc348336SMikko Perttunen 
330fc348336SMikko Perttunen 	mutex_lock(&fpriv->lock);
331fc348336SMikko Perttunen 	sp = xa_erase(&fpriv->syncpoints, args->id);
332fc348336SMikko Perttunen 	mutex_unlock(&fpriv->lock);
333fc348336SMikko Perttunen 
334fc348336SMikko Perttunen 	if (!sp)
335fc348336SMikko Perttunen 		return -EINVAL;
336fc348336SMikko Perttunen 
337fc348336SMikko Perttunen 	host1x_syncpt_put(sp);
338fc348336SMikko Perttunen 
339fc348336SMikko Perttunen 	return 0;
340fc348336SMikko Perttunen }
341fc348336SMikko Perttunen 
tegra_drm_ioctl_syncpoint_wait(struct drm_device * drm,void * data,struct drm_file * file)34244e96138SMikko Perttunen int tegra_drm_ioctl_syncpoint_wait(struct drm_device *drm, void *data, struct drm_file *file)
343d7c591bcSMikko Perttunen {
34444e96138SMikko Perttunen 	struct host1x *host1x = tegra_drm_to_host1x(drm->dev_private);
34544e96138SMikko Perttunen 	struct drm_tegra_syncpoint_wait *args = data;
34644e96138SMikko Perttunen 	signed long timeout_jiffies;
34744e96138SMikko Perttunen 	struct host1x_syncpt *sp;
348d7c591bcSMikko Perttunen 
34944e96138SMikko Perttunen 	if (args->padding != 0)
350d7c591bcSMikko Perttunen 		return -EINVAL;
351d7c591bcSMikko Perttunen 
35244e96138SMikko Perttunen 	sp = host1x_syncpt_get_by_id_noref(host1x, args->id);
35344e96138SMikko Perttunen 	if (!sp)
354d7c591bcSMikko Perttunen 		return -EINVAL;
355d7c591bcSMikko Perttunen 
35644e96138SMikko Perttunen 	timeout_jiffies = drm_timeout_abs_to_jiffies(args->timeout_ns);
357d7c591bcSMikko Perttunen 
35844e96138SMikko Perttunen 	return host1x_syncpt_wait(sp, args->threshold, timeout_jiffies, &args->value);
359d7c591bcSMikko Perttunen }
360