cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

drm_syncobj.c (42325B)


      1/*
      2 * Copyright 2017 Red Hat
      3 * Parts ported from amdgpu (fence wait code).
      4 * Copyright 2016 Advanced Micro Devices, Inc.
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a
      7 * copy of this software and associated documentation files (the "Software"),
      8 * to deal in the Software without restriction, including without limitation
      9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10 * and/or sell copies of the Software, and to permit persons to whom the
     11 * Software is furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice (including the next
     14 * paragraph) shall be included in all copies or substantial portions of the
     15 * Software.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     23 * IN THE SOFTWARE.
     24 *
     25 * Authors:
     26 *
     27 */
     28
     29/**
     30 * DOC: Overview
     31 *
     32 * DRM synchronisation objects (syncobj, see struct &drm_syncobj) provide a
     33 * container for a synchronization primitive which can be used by userspace
     34 * to explicitly synchronize GPU commands, can be shared between userspace
     35 * processes, and can be shared between different DRM drivers.
     36 * Their primary use-case is to implement Vulkan fences and semaphores.
     37 * The syncobj userspace API provides ioctls for several operations:
     38 *
     39 *  - Creation and destruction of syncobjs
     40 *  - Import and export of syncobjs to/from a syncobj file descriptor
     41 *  - Import and export a syncobj's underlying fence to/from a sync file
     42 *  - Reset a syncobj (set its fence to NULL)
     43 *  - Signal a syncobj (set a trivially signaled fence)
     44 *  - Wait for a syncobj's fence to appear and be signaled
     45 *
     46 * The syncobj userspace API also provides operations to manipulate a syncobj
     47 * in terms of a timeline of struct &dma_fence_chain rather than a single
     48 * struct &dma_fence, through the following operations:
     49 *
     50 *   - Signal a given point on the timeline
     51 *   - Wait for a given point to appear and/or be signaled
     52 *   - Import and export from/to a given point of a timeline
     53 *
     54 * At it's core, a syncobj is simply a wrapper around a pointer to a struct
     55 * &dma_fence which may be NULL.
     56 * When a syncobj is first created, its pointer is either NULL or a pointer
     57 * to an already signaled fence depending on whether the
     58 * &DRM_SYNCOBJ_CREATE_SIGNALED flag is passed to
     59 * &DRM_IOCTL_SYNCOBJ_CREATE.
     60 *
     61 * If the syncobj is considered as a binary (its state is either signaled or
     62 * unsignaled) primitive, when GPU work is enqueued in a DRM driver to signal
     63 * the syncobj, the syncobj's fence is replaced with a fence which will be
     64 * signaled by the completion of that work.
     65 * If the syncobj is considered as a timeline primitive, when GPU work is
     66 * enqueued in a DRM driver to signal the a given point of the syncobj, a new
     67 * struct &dma_fence_chain pointing to the DRM driver's fence and also
     68 * pointing to the previous fence that was in the syncobj. The new struct
     69 * &dma_fence_chain fence replace the syncobj's fence and will be signaled by
     70 * completion of the DRM driver's work and also any work associated with the
     71 * fence previously in the syncobj.
     72 *
     73 * When GPU work which waits on a syncobj is enqueued in a DRM driver, at the
     74 * time the work is enqueued, it waits on the syncobj's fence before
     75 * submitting the work to hardware. That fence is either :
     76 *
     77 *    - The syncobj's current fence if the syncobj is considered as a binary
     78 *      primitive.
     79 *    - The struct &dma_fence associated with a given point if the syncobj is
     80 *      considered as a timeline primitive.
     81 *
     82 * If the syncobj's fence is NULL or not present in the syncobj's timeline,
     83 * the enqueue operation is expected to fail.
     84 *
     85 * With binary syncobj, all manipulation of the syncobjs's fence happens in
     86 * terms of the current fence at the time the ioctl is called by userspace
     87 * regardless of whether that operation is an immediate host-side operation
     88 * (signal or reset) or or an operation which is enqueued in some driver
     89 * queue. &DRM_IOCTL_SYNCOBJ_RESET and &DRM_IOCTL_SYNCOBJ_SIGNAL can be used
     90 * to manipulate a syncobj from the host by resetting its pointer to NULL or
     91 * setting its pointer to a fence which is already signaled.
     92 *
     93 * With a timeline syncobj, all manipulation of the synobj's fence happens in
     94 * terms of a u64 value referring to point in the timeline. See
     95 * dma_fence_chain_find_seqno() to see how a given point is found in the
     96 * timeline.
     97 *
     98 * Note that applications should be careful to always use timeline set of
     99 * ioctl() when dealing with syncobj considered as timeline. Using a binary
    100 * set of ioctl() with a syncobj considered as timeline could result incorrect
    101 * synchronization. The use of binary syncobj is supported through the
    102 * timeline set of ioctl() by using a point value of 0, this will reproduce
    103 * the behavior of the binary set of ioctl() (for example replace the
    104 * syncobj's fence when signaling).
    105 *
    106 *
    107 * Host-side wait on syncobjs
    108 * --------------------------
    109 *
    110 * &DRM_IOCTL_SYNCOBJ_WAIT takes an array of syncobj handles and does a
    111 * host-side wait on all of the syncobj fences simultaneously.
    112 * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL is set, the wait ioctl will wait on
    113 * all of the syncobj fences to be signaled before it returns.
    114 * Otherwise, it returns once at least one syncobj fence has been signaled
    115 * and the index of a signaled fence is written back to the client.
    116 *
    117 * Unlike the enqueued GPU work dependencies which fail if they see a NULL
    118 * fence in a syncobj, if &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT is set,
    119 * the host-side wait will first wait for the syncobj to receive a non-NULL
    120 * fence and then wait on that fence.
    121 * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT is not set and any one of the
    122 * syncobjs in the array has a NULL fence, -EINVAL will be returned.
    123 * Assuming the syncobj starts off with a NULL fence, this allows a client
    124 * to do a host wait in one thread (or process) which waits on GPU work
    125 * submitted in another thread (or process) without having to manually
    126 * synchronize between the two.
    127 * This requirement is inherited from the Vulkan fence API.
    128 *
    129 * Similarly, &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT takes an array of syncobj
    130 * handles as well as an array of u64 points and does a host-side wait on all
    131 * of syncobj fences at the given points simultaneously.
    132 *
    133 * &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT also adds the ability to wait for a given
    134 * fence to materialize on the timeline without waiting for the fence to be
    135 * signaled by using the &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE flag. This
    136 * requirement is inherited from the wait-before-signal behavior required by
    137 * the Vulkan timeline semaphore API.
    138 *
    139 *
    140 * Import/export of syncobjs
    141 * -------------------------
    142 *
    143 * &DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE and &DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
    144 * provide two mechanisms for import/export of syncobjs.
    145 *
    146 * The first lets the client import or export an entire syncobj to a file
    147 * descriptor.
    148 * These fd's are opaque and have no other use case, except passing the
    149 * syncobj between processes.
    150 * All exported file descriptors and any syncobj handles created as a
    151 * result of importing those file descriptors own a reference to the
    152 * same underlying struct &drm_syncobj and the syncobj can be used
    153 * persistently across all the processes with which it is shared.
    154 * The syncobj is freed only once the last reference is dropped.
    155 * Unlike dma-buf, importing a syncobj creates a new handle (with its own
    156 * reference) for every import instead of de-duplicating.
    157 * The primary use-case of this persistent import/export is for shared
    158 * Vulkan fences and semaphores.
    159 *
    160 * The second import/export mechanism, which is indicated by
    161 * &DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE or
    162 * &DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE lets the client
    163 * import/export the syncobj's current fence from/to a &sync_file.
    164 * When a syncobj is exported to a sync file, that sync file wraps the
    165 * sycnobj's fence at the time of export and any later signal or reset
    166 * operations on the syncobj will not affect the exported sync file.
    167 * When a sync file is imported into a syncobj, the syncobj's fence is set
    168 * to the fence wrapped by that sync file.
    169 * Because sync files are immutable, resetting or signaling the syncobj
    170 * will not affect any sync files whose fences have been imported into the
    171 * syncobj.
    172 *
    173 *
    174 * Import/export of timeline points in timeline syncobjs
    175 * -----------------------------------------------------
    176 *
    177 * &DRM_IOCTL_SYNCOBJ_TRANSFER provides a mechanism to transfer a struct
    178 * &dma_fence_chain of a syncobj at a given u64 point to another u64 point
    179 * into another syncobj.
    180 *
    181 * Note that if you want to transfer a struct &dma_fence_chain from a given
    182 * point on a timeline syncobj from/into a binary syncobj, you can use the
    183 * point 0 to mean take/replace the fence in the syncobj.
    184 */
    185
    186#include <linux/anon_inodes.h>
    187#include <linux/file.h>
    188#include <linux/fs.h>
    189#include <linux/sched/signal.h>
    190#include <linux/sync_file.h>
    191#include <linux/uaccess.h>
    192
    193#include <drm/drm.h>
    194#include <drm/drm_drv.h>
    195#include <drm/drm_file.h>
    196#include <drm/drm_gem.h>
    197#include <drm/drm_print.h>
    198#include <drm/drm_syncobj.h>
    199#include <drm/drm_utils.h>
    200
    201#include "drm_internal.h"
    202
    203struct syncobj_wait_entry {
    204	struct list_head node;
    205	struct task_struct *task;
    206	struct dma_fence *fence;
    207	struct dma_fence_cb fence_cb;
    208	u64    point;
    209};
    210
    211static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
    212				      struct syncobj_wait_entry *wait);
    213
    214/**
    215 * drm_syncobj_find - lookup and reference a sync object.
    216 * @file_private: drm file private pointer
    217 * @handle: sync object handle to lookup.
    218 *
    219 * Returns a reference to the syncobj pointed to by handle or NULL. The
    220 * reference must be released by calling drm_syncobj_put().
    221 */
    222struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
    223				     u32 handle)
    224{
    225	struct drm_syncobj *syncobj;
    226
    227	spin_lock(&file_private->syncobj_table_lock);
    228
    229	/* Check if we currently have a reference on the object */
    230	syncobj = idr_find(&file_private->syncobj_idr, handle);
    231	if (syncobj)
    232		drm_syncobj_get(syncobj);
    233
    234	spin_unlock(&file_private->syncobj_table_lock);
    235
    236	return syncobj;
    237}
    238EXPORT_SYMBOL(drm_syncobj_find);
    239
    240static void drm_syncobj_fence_add_wait(struct drm_syncobj *syncobj,
    241				       struct syncobj_wait_entry *wait)
    242{
    243	struct dma_fence *fence;
    244
    245	if (wait->fence)
    246		return;
    247
    248	spin_lock(&syncobj->lock);
    249	/* We've already tried once to get a fence and failed.  Now that we
    250	 * have the lock, try one more time just to be sure we don't add a
    251	 * callback when a fence has already been set.
    252	 */
    253	fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, 1));
    254	if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) {
    255		dma_fence_put(fence);
    256		list_add_tail(&wait->node, &syncobj->cb_list);
    257	} else if (!fence) {
    258		wait->fence = dma_fence_get_stub();
    259	} else {
    260		wait->fence = fence;
    261	}
    262	spin_unlock(&syncobj->lock);
    263}
    264
    265static void drm_syncobj_remove_wait(struct drm_syncobj *syncobj,
    266				    struct syncobj_wait_entry *wait)
    267{
    268	if (!wait->node.next)
    269		return;
    270
    271	spin_lock(&syncobj->lock);
    272	list_del_init(&wait->node);
    273	spin_unlock(&syncobj->lock);
    274}
    275
    276/**
    277 * drm_syncobj_add_point - add new timeline point to the syncobj
    278 * @syncobj: sync object to add timeline point do
    279 * @chain: chain node to use to add the point
    280 * @fence: fence to encapsulate in the chain node
    281 * @point: sequence number to use for the point
    282 *
    283 * Add the chain node as new timeline point to the syncobj.
    284 */
    285void drm_syncobj_add_point(struct drm_syncobj *syncobj,
    286			   struct dma_fence_chain *chain,
    287			   struct dma_fence *fence,
    288			   uint64_t point)
    289{
    290	struct syncobj_wait_entry *cur, *tmp;
    291	struct dma_fence *prev;
    292
    293	dma_fence_get(fence);
    294
    295	spin_lock(&syncobj->lock);
    296
    297	prev = drm_syncobj_fence_get(syncobj);
    298	/* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */
    299	if (prev && prev->seqno >= point)
    300		DRM_DEBUG("You are adding an unorder point to timeline!\n");
    301	dma_fence_chain_init(chain, prev, fence, point);
    302	rcu_assign_pointer(syncobj->fence, &chain->base);
    303
    304	list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node)
    305		syncobj_wait_syncobj_func(syncobj, cur);
    306	spin_unlock(&syncobj->lock);
    307
    308	/* Walk the chain once to trigger garbage collection */
    309	dma_fence_chain_for_each(fence, prev);
    310	dma_fence_put(prev);
    311}
    312EXPORT_SYMBOL(drm_syncobj_add_point);
    313
    314/**
    315 * drm_syncobj_replace_fence - replace fence in a sync object.
    316 * @syncobj: Sync object to replace fence in
    317 * @fence: fence to install in sync file.
    318 *
    319 * This replaces the fence on a sync object.
    320 */
    321void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
    322			       struct dma_fence *fence)
    323{
    324	struct dma_fence *old_fence;
    325	struct syncobj_wait_entry *cur, *tmp;
    326
    327	if (fence)
    328		dma_fence_get(fence);
    329
    330	spin_lock(&syncobj->lock);
    331
    332	old_fence = rcu_dereference_protected(syncobj->fence,
    333					      lockdep_is_held(&syncobj->lock));
    334	rcu_assign_pointer(syncobj->fence, fence);
    335
    336	if (fence != old_fence) {
    337		list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node)
    338			syncobj_wait_syncobj_func(syncobj, cur);
    339	}
    340
    341	spin_unlock(&syncobj->lock);
    342
    343	dma_fence_put(old_fence);
    344}
    345EXPORT_SYMBOL(drm_syncobj_replace_fence);
    346
    347/**
    348 * drm_syncobj_assign_null_handle - assign a stub fence to the sync object
    349 * @syncobj: sync object to assign the fence on
    350 *
    351 * Assign a already signaled stub fence to the sync object.
    352 */
    353static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
    354{
    355	struct dma_fence *fence = dma_fence_allocate_private_stub();
    356
    357	if (IS_ERR(fence))
    358		return PTR_ERR(fence);
    359
    360	drm_syncobj_replace_fence(syncobj, fence);
    361	dma_fence_put(fence);
    362	return 0;
    363}
    364
    365/* 5s default for wait submission */
    366#define DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT 5000000000ULL
    367/**
    368 * drm_syncobj_find_fence - lookup and reference the fence in a sync object
    369 * @file_private: drm file private pointer
    370 * @handle: sync object handle to lookup.
    371 * @point: timeline point
    372 * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not
    373 * @fence: out parameter for the fence
    374 *
    375 * This is just a convenience function that combines drm_syncobj_find() and
    376 * drm_syncobj_fence_get().
    377 *
    378 * Returns 0 on success or a negative error value on failure. On success @fence
    379 * contains a reference to the fence, which must be released by calling
    380 * dma_fence_put().
    381 */
    382int drm_syncobj_find_fence(struct drm_file *file_private,
    383			   u32 handle, u64 point, u64 flags,
    384			   struct dma_fence **fence)
    385{
    386	struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
    387	struct syncobj_wait_entry wait;
    388	u64 timeout = nsecs_to_jiffies64(DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT);
    389	int ret;
    390
    391	if (!syncobj)
    392		return -ENOENT;
    393
    394	/* Waiting for userspace with locks help is illegal cause that can
    395	 * trivial deadlock with page faults for example. Make lockdep complain
    396	 * about it early on.
    397	 */
    398	if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
    399		might_sleep();
    400		lockdep_assert_none_held_once();
    401	}
    402
    403	*fence = drm_syncobj_fence_get(syncobj);
    404
    405	if (*fence) {
    406		ret = dma_fence_chain_find_seqno(fence, point);
    407		if (!ret) {
    408			/* If the requested seqno is already signaled
    409			 * drm_syncobj_find_fence may return a NULL
    410			 * fence. To make sure the recipient gets
    411			 * signalled, use a new fence instead.
    412			 */
    413			if (!*fence)
    414				*fence = dma_fence_get_stub();
    415
    416			goto out;
    417		}
    418		dma_fence_put(*fence);
    419	} else {
    420		ret = -EINVAL;
    421	}
    422
    423	if (!(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
    424		goto out;
    425
    426	memset(&wait, 0, sizeof(wait));
    427	wait.task = current;
    428	wait.point = point;
    429	drm_syncobj_fence_add_wait(syncobj, &wait);
    430
    431	do {
    432		set_current_state(TASK_INTERRUPTIBLE);
    433		if (wait.fence) {
    434			ret = 0;
    435			break;
    436		}
    437                if (timeout == 0) {
    438                        ret = -ETIME;
    439                        break;
    440                }
    441
    442		if (signal_pending(current)) {
    443			ret = -ERESTARTSYS;
    444			break;
    445		}
    446
    447                timeout = schedule_timeout(timeout);
    448	} while (1);
    449
    450	__set_current_state(TASK_RUNNING);
    451	*fence = wait.fence;
    452
    453	if (wait.node.next)
    454		drm_syncobj_remove_wait(syncobj, &wait);
    455
    456out:
    457	drm_syncobj_put(syncobj);
    458
    459	return ret;
    460}
    461EXPORT_SYMBOL(drm_syncobj_find_fence);
    462
    463/**
    464 * drm_syncobj_free - free a sync object.
    465 * @kref: kref to free.
    466 *
    467 * Only to be called from kref_put in drm_syncobj_put.
    468 */
    469void drm_syncobj_free(struct kref *kref)
    470{
    471	struct drm_syncobj *syncobj = container_of(kref,
    472						   struct drm_syncobj,
    473						   refcount);
    474	drm_syncobj_replace_fence(syncobj, NULL);
    475	kfree(syncobj);
    476}
    477EXPORT_SYMBOL(drm_syncobj_free);
    478
    479/**
    480 * drm_syncobj_create - create a new syncobj
    481 * @out_syncobj: returned syncobj
    482 * @flags: DRM_SYNCOBJ_* flags
    483 * @fence: if non-NULL, the syncobj will represent this fence
    484 *
    485 * This is the first function to create a sync object. After creating, drivers
    486 * probably want to make it available to userspace, either through
    487 * drm_syncobj_get_handle() or drm_syncobj_get_fd().
    488 *
    489 * Returns 0 on success or a negative error value on failure.
    490 */
    491int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
    492		       struct dma_fence *fence)
    493{
    494	int ret;
    495	struct drm_syncobj *syncobj;
    496
    497	syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL);
    498	if (!syncobj)
    499		return -ENOMEM;
    500
    501	kref_init(&syncobj->refcount);
    502	INIT_LIST_HEAD(&syncobj->cb_list);
    503	spin_lock_init(&syncobj->lock);
    504
    505	if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
    506		ret = drm_syncobj_assign_null_handle(syncobj);
    507		if (ret < 0) {
    508			drm_syncobj_put(syncobj);
    509			return ret;
    510		}
    511	}
    512
    513	if (fence)
    514		drm_syncobj_replace_fence(syncobj, fence);
    515
    516	*out_syncobj = syncobj;
    517	return 0;
    518}
    519EXPORT_SYMBOL(drm_syncobj_create);
    520
    521/**
    522 * drm_syncobj_get_handle - get a handle from a syncobj
    523 * @file_private: drm file private pointer
    524 * @syncobj: Sync object to export
    525 * @handle: out parameter with the new handle
    526 *
    527 * Exports a sync object created with drm_syncobj_create() as a handle on
    528 * @file_private to userspace.
    529 *
    530 * Returns 0 on success or a negative error value on failure.
    531 */
    532int drm_syncobj_get_handle(struct drm_file *file_private,
    533			   struct drm_syncobj *syncobj, u32 *handle)
    534{
    535	int ret;
    536
    537	/* take a reference to put in the idr */
    538	drm_syncobj_get(syncobj);
    539
    540	idr_preload(GFP_KERNEL);
    541	spin_lock(&file_private->syncobj_table_lock);
    542	ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
    543	spin_unlock(&file_private->syncobj_table_lock);
    544
    545	idr_preload_end();
    546
    547	if (ret < 0) {
    548		drm_syncobj_put(syncobj);
    549		return ret;
    550	}
    551
    552	*handle = ret;
    553	return 0;
    554}
    555EXPORT_SYMBOL(drm_syncobj_get_handle);
    556
    557static int drm_syncobj_create_as_handle(struct drm_file *file_private,
    558					u32 *handle, uint32_t flags)
    559{
    560	int ret;
    561	struct drm_syncobj *syncobj;
    562
    563	ret = drm_syncobj_create(&syncobj, flags, NULL);
    564	if (ret)
    565		return ret;
    566
    567	ret = drm_syncobj_get_handle(file_private, syncobj, handle);
    568	drm_syncobj_put(syncobj);
    569	return ret;
    570}
    571
    572static int drm_syncobj_destroy(struct drm_file *file_private,
    573			       u32 handle)
    574{
    575	struct drm_syncobj *syncobj;
    576
    577	spin_lock(&file_private->syncobj_table_lock);
    578	syncobj = idr_remove(&file_private->syncobj_idr, handle);
    579	spin_unlock(&file_private->syncobj_table_lock);
    580
    581	if (!syncobj)
    582		return -EINVAL;
    583
    584	drm_syncobj_put(syncobj);
    585	return 0;
    586}
    587
    588static int drm_syncobj_file_release(struct inode *inode, struct file *file)
    589{
    590	struct drm_syncobj *syncobj = file->private_data;
    591
    592	drm_syncobj_put(syncobj);
    593	return 0;
    594}
    595
    596static const struct file_operations drm_syncobj_file_fops = {
    597	.release = drm_syncobj_file_release,
    598};
    599
    600/**
    601 * drm_syncobj_get_fd - get a file descriptor from a syncobj
    602 * @syncobj: Sync object to export
    603 * @p_fd: out parameter with the new file descriptor
    604 *
    605 * Exports a sync object created with drm_syncobj_create() as a file descriptor.
    606 *
    607 * Returns 0 on success or a negative error value on failure.
    608 */
    609int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)
    610{
    611	struct file *file;
    612	int fd;
    613
    614	fd = get_unused_fd_flags(O_CLOEXEC);
    615	if (fd < 0)
    616		return fd;
    617
    618	file = anon_inode_getfile("syncobj_file",
    619				  &drm_syncobj_file_fops,
    620				  syncobj, 0);
    621	if (IS_ERR(file)) {
    622		put_unused_fd(fd);
    623		return PTR_ERR(file);
    624	}
    625
    626	drm_syncobj_get(syncobj);
    627	fd_install(fd, file);
    628
    629	*p_fd = fd;
    630	return 0;
    631}
    632EXPORT_SYMBOL(drm_syncobj_get_fd);
    633
    634static int drm_syncobj_handle_to_fd(struct drm_file *file_private,
    635				    u32 handle, int *p_fd)
    636{
    637	struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
    638	int ret;
    639
    640	if (!syncobj)
    641		return -EINVAL;
    642
    643	ret = drm_syncobj_get_fd(syncobj, p_fd);
    644	drm_syncobj_put(syncobj);
    645	return ret;
    646}
    647
    648static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
    649				    int fd, u32 *handle)
    650{
    651	struct drm_syncobj *syncobj;
    652	struct fd f = fdget(fd);
    653	int ret;
    654
    655	if (!f.file)
    656		return -EINVAL;
    657
    658	if (f.file->f_op != &drm_syncobj_file_fops) {
    659		fdput(f);
    660		return -EINVAL;
    661	}
    662
    663	/* take a reference to put in the idr */
    664	syncobj = f.file->private_data;
    665	drm_syncobj_get(syncobj);
    666
    667	idr_preload(GFP_KERNEL);
    668	spin_lock(&file_private->syncobj_table_lock);
    669	ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
    670	spin_unlock(&file_private->syncobj_table_lock);
    671	idr_preload_end();
    672
    673	if (ret > 0) {
    674		*handle = ret;
    675		ret = 0;
    676	} else
    677		drm_syncobj_put(syncobj);
    678
    679	fdput(f);
    680	return ret;
    681}
    682
    683static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
    684					      int fd, int handle)
    685{
    686	struct dma_fence *fence = sync_file_get_fence(fd);
    687	struct drm_syncobj *syncobj;
    688
    689	if (!fence)
    690		return -EINVAL;
    691
    692	syncobj = drm_syncobj_find(file_private, handle);
    693	if (!syncobj) {
    694		dma_fence_put(fence);
    695		return -ENOENT;
    696	}
    697
    698	drm_syncobj_replace_fence(syncobj, fence);
    699	dma_fence_put(fence);
    700	drm_syncobj_put(syncobj);
    701	return 0;
    702}
    703
    704static int drm_syncobj_export_sync_file(struct drm_file *file_private,
    705					int handle, int *p_fd)
    706{
    707	int ret;
    708	struct dma_fence *fence;
    709	struct sync_file *sync_file;
    710	int fd = get_unused_fd_flags(O_CLOEXEC);
    711
    712	if (fd < 0)
    713		return fd;
    714
    715	ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence);
    716	if (ret)
    717		goto err_put_fd;
    718
    719	sync_file = sync_file_create(fence);
    720
    721	dma_fence_put(fence);
    722
    723	if (!sync_file) {
    724		ret = -EINVAL;
    725		goto err_put_fd;
    726	}
    727
    728	fd_install(fd, sync_file->file);
    729
    730	*p_fd = fd;
    731	return 0;
    732err_put_fd:
    733	put_unused_fd(fd);
    734	return ret;
    735}
    736/**
    737 * drm_syncobj_open - initializes syncobj file-private structures at devnode open time
    738 * @file_private: drm file-private structure to set up
    739 *
    740 * Called at device open time, sets up the structure for handling refcounting
    741 * of sync objects.
    742 */
    743void
    744drm_syncobj_open(struct drm_file *file_private)
    745{
    746	idr_init_base(&file_private->syncobj_idr, 1);
    747	spin_lock_init(&file_private->syncobj_table_lock);
    748}
    749
    750static int
    751drm_syncobj_release_handle(int id, void *ptr, void *data)
    752{
    753	struct drm_syncobj *syncobj = ptr;
    754
    755	drm_syncobj_put(syncobj);
    756	return 0;
    757}
    758
    759/**
    760 * drm_syncobj_release - release file-private sync object resources
    761 * @file_private: drm file-private structure to clean up
    762 *
    763 * Called at close time when the filp is going away.
    764 *
    765 * Releases any remaining references on objects by this filp.
    766 */
    767void
    768drm_syncobj_release(struct drm_file *file_private)
    769{
    770	idr_for_each(&file_private->syncobj_idr,
    771		     &drm_syncobj_release_handle, file_private);
    772	idr_destroy(&file_private->syncobj_idr);
    773}
    774
    775int
    776drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
    777			 struct drm_file *file_private)
    778{
    779	struct drm_syncobj_create *args = data;
    780
    781	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
    782		return -EOPNOTSUPP;
    783
    784	/* no valid flags yet */
    785	if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
    786		return -EINVAL;
    787
    788	return drm_syncobj_create_as_handle(file_private,
    789					    &args->handle, args->flags);
    790}
    791
    792int
    793drm_syncobj_destroy_ioctl(struct drm_device *dev, void *data,
    794			  struct drm_file *file_private)
    795{
    796	struct drm_syncobj_destroy *args = data;
    797
    798	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
    799		return -EOPNOTSUPP;
    800
    801	/* make sure padding is empty */
    802	if (args->pad)
    803		return -EINVAL;
    804	return drm_syncobj_destroy(file_private, args->handle);
    805}
    806
    807int
    808drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
    809				   struct drm_file *file_private)
    810{
    811	struct drm_syncobj_handle *args = data;
    812
    813	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
    814		return -EOPNOTSUPP;
    815
    816	if (args->pad)
    817		return -EINVAL;
    818
    819	if (args->flags != 0 &&
    820	    args->flags != DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
    821		return -EINVAL;
    822
    823	if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
    824		return drm_syncobj_export_sync_file(file_private, args->handle,
    825						    &args->fd);
    826
    827	return drm_syncobj_handle_to_fd(file_private, args->handle,
    828					&args->fd);
    829}
    830
    831int
    832drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
    833				   struct drm_file *file_private)
    834{
    835	struct drm_syncobj_handle *args = data;
    836
    837	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
    838		return -EOPNOTSUPP;
    839
    840	if (args->pad)
    841		return -EINVAL;
    842
    843	if (args->flags != 0 &&
    844	    args->flags != DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
    845		return -EINVAL;
    846
    847	if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
    848		return drm_syncobj_import_sync_file_fence(file_private,
    849							  args->fd,
    850							  args->handle);
    851
    852	return drm_syncobj_fd_to_handle(file_private, args->fd,
    853					&args->handle);
    854}
    855
    856
    857/*
    858 * Try to flatten a dma_fence_chain into a dma_fence_array so that it can be
    859 * added as timeline fence to a chain again.
    860 */
    861static int drm_syncobj_flatten_chain(struct dma_fence **f)
    862{
    863	struct dma_fence_chain *chain = to_dma_fence_chain(*f);
    864	struct dma_fence *tmp, **fences;
    865	struct dma_fence_array *array;
    866	unsigned int count;
    867
    868	if (!chain)
    869		return 0;
    870
    871	count = 0;
    872	dma_fence_chain_for_each(tmp, &chain->base)
    873		++count;
    874
    875	fences = kmalloc_array(count, sizeof(*fences), GFP_KERNEL);
    876	if (!fences)
    877		return -ENOMEM;
    878
    879	count = 0;
    880	dma_fence_chain_for_each(tmp, &chain->base)
    881		fences[count++] = dma_fence_get(tmp);
    882
    883	array = dma_fence_array_create(count, fences,
    884				       dma_fence_context_alloc(1),
    885				       1, false);
    886	if (!array)
    887		goto free_fences;
    888
    889	dma_fence_put(*f);
    890	*f = &array->base;
    891	return 0;
    892
    893free_fences:
    894	while (count--)
    895		dma_fence_put(fences[count]);
    896
    897	kfree(fences);
    898	return -ENOMEM;
    899}
    900
    901static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private,
    902					    struct drm_syncobj_transfer *args)
    903{
    904	struct drm_syncobj *timeline_syncobj = NULL;
    905	struct dma_fence_chain *chain;
    906	struct dma_fence *fence;
    907	int ret;
    908
    909	timeline_syncobj = drm_syncobj_find(file_private, args->dst_handle);
    910	if (!timeline_syncobj) {
    911		return -ENOENT;
    912	}
    913	ret = drm_syncobj_find_fence(file_private, args->src_handle,
    914				     args->src_point, args->flags,
    915				     &fence);
    916	if (ret)
    917		goto err_put_timeline;
    918
    919	ret = drm_syncobj_flatten_chain(&fence);
    920	if (ret)
    921		goto err_free_fence;
    922
    923	chain = dma_fence_chain_alloc();
    924	if (!chain) {
    925		ret = -ENOMEM;
    926		goto err_free_fence;
    927	}
    928
    929	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->dst_point);
    930err_free_fence:
    931	dma_fence_put(fence);
    932err_put_timeline:
    933	drm_syncobj_put(timeline_syncobj);
    934
    935	return ret;
    936}
    937
    938static int
    939drm_syncobj_transfer_to_binary(struct drm_file *file_private,
    940			       struct drm_syncobj_transfer *args)
    941{
    942	struct drm_syncobj *binary_syncobj = NULL;
    943	struct dma_fence *fence;
    944	int ret;
    945
    946	binary_syncobj = drm_syncobj_find(file_private, args->dst_handle);
    947	if (!binary_syncobj)
    948		return -ENOENT;
    949	ret = drm_syncobj_find_fence(file_private, args->src_handle,
    950				     args->src_point, args->flags, &fence);
    951	if (ret)
    952		goto err;
    953	drm_syncobj_replace_fence(binary_syncobj, fence);
    954	dma_fence_put(fence);
    955err:
    956	drm_syncobj_put(binary_syncobj);
    957
    958	return ret;
    959}
    960int
    961drm_syncobj_transfer_ioctl(struct drm_device *dev, void *data,
    962			   struct drm_file *file_private)
    963{
    964	struct drm_syncobj_transfer *args = data;
    965	int ret;
    966
    967	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
    968		return -EOPNOTSUPP;
    969
    970	if (args->pad)
    971		return -EINVAL;
    972
    973	if (args->dst_point)
    974		ret = drm_syncobj_transfer_to_timeline(file_private, args);
    975	else
    976		ret = drm_syncobj_transfer_to_binary(file_private, args);
    977
    978	return ret;
    979}
    980
    981static void syncobj_wait_fence_func(struct dma_fence *fence,
    982				    struct dma_fence_cb *cb)
    983{
    984	struct syncobj_wait_entry *wait =
    985		container_of(cb, struct syncobj_wait_entry, fence_cb);
    986
    987	wake_up_process(wait->task);
    988}
    989
    990static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
    991				      struct syncobj_wait_entry *wait)
    992{
    993	struct dma_fence *fence;
    994
    995	/* This happens inside the syncobj lock */
    996	fence = rcu_dereference_protected(syncobj->fence,
    997					  lockdep_is_held(&syncobj->lock));
    998	dma_fence_get(fence);
    999	if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) {
   1000		dma_fence_put(fence);
   1001		return;
   1002	} else if (!fence) {
   1003		wait->fence = dma_fence_get_stub();
   1004	} else {
   1005		wait->fence = fence;
   1006	}
   1007
   1008	wake_up_process(wait->task);
   1009	list_del_init(&wait->node);
   1010}
   1011
   1012static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
   1013						  void __user *user_points,
   1014						  uint32_t count,
   1015						  uint32_t flags,
   1016						  signed long timeout,
   1017						  uint32_t *idx)
   1018{
   1019	struct syncobj_wait_entry *entries;
   1020	struct dma_fence *fence;
   1021	uint64_t *points;
   1022	uint32_t signaled_count, i;
   1023
   1024	if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)
   1025		lockdep_assert_none_held_once();
   1026
   1027	points = kmalloc_array(count, sizeof(*points), GFP_KERNEL);
   1028	if (points == NULL)
   1029		return -ENOMEM;
   1030
   1031	if (!user_points) {
   1032		memset(points, 0, count * sizeof(uint64_t));
   1033
   1034	} else if (copy_from_user(points, user_points,
   1035				  sizeof(uint64_t) * count)) {
   1036		timeout = -EFAULT;
   1037		goto err_free_points;
   1038	}
   1039
   1040	entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
   1041	if (!entries) {
   1042		timeout = -ENOMEM;
   1043		goto err_free_points;
   1044	}
   1045	/* Walk the list of sync objects and initialize entries.  We do
   1046	 * this up-front so that we can properly return -EINVAL if there is
   1047	 * a syncobj with a missing fence and then never have the chance of
   1048	 * returning -EINVAL again.
   1049	 */
   1050	signaled_count = 0;
   1051	for (i = 0; i < count; ++i) {
   1052		struct dma_fence *fence;
   1053
   1054		entries[i].task = current;
   1055		entries[i].point = points[i];
   1056		fence = drm_syncobj_fence_get(syncobjs[i]);
   1057		if (!fence || dma_fence_chain_find_seqno(&fence, points[i])) {
   1058			dma_fence_put(fence);
   1059			if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
   1060				continue;
   1061			} else {
   1062				timeout = -EINVAL;
   1063				goto cleanup_entries;
   1064			}
   1065		}
   1066
   1067		if (fence)
   1068			entries[i].fence = fence;
   1069		else
   1070			entries[i].fence = dma_fence_get_stub();
   1071
   1072		if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) ||
   1073		    dma_fence_is_signaled(entries[i].fence)) {
   1074			if (signaled_count == 0 && idx)
   1075				*idx = i;
   1076			signaled_count++;
   1077		}
   1078	}
   1079
   1080	if (signaled_count == count ||
   1081	    (signaled_count > 0 &&
   1082	     !(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)))
   1083		goto cleanup_entries;
   1084
   1085	/* There's a very annoying laxness in the dma_fence API here, in
   1086	 * that backends are not required to automatically report when a
   1087	 * fence is signaled prior to fence->ops->enable_signaling() being
   1088	 * called.  So here if we fail to match signaled_count, we need to
   1089	 * fallthough and try a 0 timeout wait!
   1090	 */
   1091
   1092	if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
   1093		for (i = 0; i < count; ++i)
   1094			drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]);
   1095	}
   1096
   1097	do {
   1098		set_current_state(TASK_INTERRUPTIBLE);
   1099
   1100		signaled_count = 0;
   1101		for (i = 0; i < count; ++i) {
   1102			fence = entries[i].fence;
   1103			if (!fence)
   1104				continue;
   1105
   1106			if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) ||
   1107			    dma_fence_is_signaled(fence) ||
   1108			    (!entries[i].fence_cb.func &&
   1109			     dma_fence_add_callback(fence,
   1110						    &entries[i].fence_cb,
   1111						    syncobj_wait_fence_func))) {
   1112				/* The fence has been signaled */
   1113				if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) {
   1114					signaled_count++;
   1115				} else {
   1116					if (idx)
   1117						*idx = i;
   1118					goto done_waiting;
   1119				}
   1120			}
   1121		}
   1122
   1123		if (signaled_count == count)
   1124			goto done_waiting;
   1125
   1126		if (timeout == 0) {
   1127			timeout = -ETIME;
   1128			goto done_waiting;
   1129		}
   1130
   1131		if (signal_pending(current)) {
   1132			timeout = -ERESTARTSYS;
   1133			goto done_waiting;
   1134		}
   1135
   1136		timeout = schedule_timeout(timeout);
   1137	} while (1);
   1138
   1139done_waiting:
   1140	__set_current_state(TASK_RUNNING);
   1141
   1142cleanup_entries:
   1143	for (i = 0; i < count; ++i) {
   1144		drm_syncobj_remove_wait(syncobjs[i], &entries[i]);
   1145		if (entries[i].fence_cb.func)
   1146			dma_fence_remove_callback(entries[i].fence,
   1147						  &entries[i].fence_cb);
   1148		dma_fence_put(entries[i].fence);
   1149	}
   1150	kfree(entries);
   1151
   1152err_free_points:
   1153	kfree(points);
   1154
   1155	return timeout;
   1156}
   1157
   1158/**
   1159 * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
   1160 *
   1161 * @timeout_nsec: timeout nsec component in ns, 0 for poll
   1162 *
   1163 * Calculate the timeout in jiffies from an absolute time in sec/nsec.
   1164 */
   1165signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
   1166{
   1167	ktime_t abs_timeout, now;
   1168	u64 timeout_ns, timeout_jiffies64;
   1169
   1170	/* make 0 timeout means poll - absolute 0 doesn't seem valid */
   1171	if (timeout_nsec == 0)
   1172		return 0;
   1173
   1174	abs_timeout = ns_to_ktime(timeout_nsec);
   1175	now = ktime_get();
   1176
   1177	if (!ktime_after(abs_timeout, now))
   1178		return 0;
   1179
   1180	timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now));
   1181
   1182	timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns);
   1183	/*  clamp timeout to avoid infinite timeout */
   1184	if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1)
   1185		return MAX_SCHEDULE_TIMEOUT - 1;
   1186
   1187	return timeout_jiffies64 + 1;
   1188}
   1189EXPORT_SYMBOL(drm_timeout_abs_to_jiffies);
   1190
   1191static int drm_syncobj_array_wait(struct drm_device *dev,
   1192				  struct drm_file *file_private,
   1193				  struct drm_syncobj_wait *wait,
   1194				  struct drm_syncobj_timeline_wait *timeline_wait,
   1195				  struct drm_syncobj **syncobjs, bool timeline)
   1196{
   1197	signed long timeout = 0;
   1198	uint32_t first = ~0;
   1199
   1200	if (!timeline) {
   1201		timeout = drm_timeout_abs_to_jiffies(wait->timeout_nsec);
   1202		timeout = drm_syncobj_array_wait_timeout(syncobjs,
   1203							 NULL,
   1204							 wait->count_handles,
   1205							 wait->flags,
   1206							 timeout, &first);
   1207		if (timeout < 0)
   1208			return timeout;
   1209		wait->first_signaled = first;
   1210	} else {
   1211		timeout = drm_timeout_abs_to_jiffies(timeline_wait->timeout_nsec);
   1212		timeout = drm_syncobj_array_wait_timeout(syncobjs,
   1213							 u64_to_user_ptr(timeline_wait->points),
   1214							 timeline_wait->count_handles,
   1215							 timeline_wait->flags,
   1216							 timeout, &first);
   1217		if (timeout < 0)
   1218			return timeout;
   1219		timeline_wait->first_signaled = first;
   1220	}
   1221	return 0;
   1222}
   1223
   1224static int drm_syncobj_array_find(struct drm_file *file_private,
   1225				  void __user *user_handles,
   1226				  uint32_t count_handles,
   1227				  struct drm_syncobj ***syncobjs_out)
   1228{
   1229	uint32_t i, *handles;
   1230	struct drm_syncobj **syncobjs;
   1231	int ret;
   1232
   1233	handles = kmalloc_array(count_handles, sizeof(*handles), GFP_KERNEL);
   1234	if (handles == NULL)
   1235		return -ENOMEM;
   1236
   1237	if (copy_from_user(handles, user_handles,
   1238			   sizeof(uint32_t) * count_handles)) {
   1239		ret = -EFAULT;
   1240		goto err_free_handles;
   1241	}
   1242
   1243	syncobjs = kmalloc_array(count_handles, sizeof(*syncobjs), GFP_KERNEL);
   1244	if (syncobjs == NULL) {
   1245		ret = -ENOMEM;
   1246		goto err_free_handles;
   1247	}
   1248
   1249	for (i = 0; i < count_handles; i++) {
   1250		syncobjs[i] = drm_syncobj_find(file_private, handles[i]);
   1251		if (!syncobjs[i]) {
   1252			ret = -ENOENT;
   1253			goto err_put_syncobjs;
   1254		}
   1255	}
   1256
   1257	kfree(handles);
   1258	*syncobjs_out = syncobjs;
   1259	return 0;
   1260
   1261err_put_syncobjs:
   1262	while (i-- > 0)
   1263		drm_syncobj_put(syncobjs[i]);
   1264	kfree(syncobjs);
   1265err_free_handles:
   1266	kfree(handles);
   1267
   1268	return ret;
   1269}
   1270
   1271static void drm_syncobj_array_free(struct drm_syncobj **syncobjs,
   1272				   uint32_t count)
   1273{
   1274	uint32_t i;
   1275
   1276	for (i = 0; i < count; i++)
   1277		drm_syncobj_put(syncobjs[i]);
   1278	kfree(syncobjs);
   1279}
   1280
   1281int
   1282drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
   1283		       struct drm_file *file_private)
   1284{
   1285	struct drm_syncobj_wait *args = data;
   1286	struct drm_syncobj **syncobjs;
   1287	int ret = 0;
   1288
   1289	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
   1290		return -EOPNOTSUPP;
   1291
   1292	if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
   1293			    DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
   1294		return -EINVAL;
   1295
   1296	if (args->count_handles == 0)
   1297		return -EINVAL;
   1298
   1299	ret = drm_syncobj_array_find(file_private,
   1300				     u64_to_user_ptr(args->handles),
   1301				     args->count_handles,
   1302				     &syncobjs);
   1303	if (ret < 0)
   1304		return ret;
   1305
   1306	ret = drm_syncobj_array_wait(dev, file_private,
   1307				     args, NULL, syncobjs, false);
   1308
   1309	drm_syncobj_array_free(syncobjs, args->count_handles);
   1310
   1311	return ret;
   1312}
   1313
   1314int
   1315drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,
   1316				struct drm_file *file_private)
   1317{
   1318	struct drm_syncobj_timeline_wait *args = data;
   1319	struct drm_syncobj **syncobjs;
   1320	int ret = 0;
   1321
   1322	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
   1323		return -EOPNOTSUPP;
   1324
   1325	if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
   1326			    DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
   1327			    DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE))
   1328		return -EINVAL;
   1329
   1330	if (args->count_handles == 0)
   1331		return -EINVAL;
   1332
   1333	ret = drm_syncobj_array_find(file_private,
   1334				     u64_to_user_ptr(args->handles),
   1335				     args->count_handles,
   1336				     &syncobjs);
   1337	if (ret < 0)
   1338		return ret;
   1339
   1340	ret = drm_syncobj_array_wait(dev, file_private,
   1341				     NULL, args, syncobjs, true);
   1342
   1343	drm_syncobj_array_free(syncobjs, args->count_handles);
   1344
   1345	return ret;
   1346}
   1347
   1348
   1349int
   1350drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
   1351			struct drm_file *file_private)
   1352{
   1353	struct drm_syncobj_array *args = data;
   1354	struct drm_syncobj **syncobjs;
   1355	uint32_t i;
   1356	int ret;
   1357
   1358	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
   1359		return -EOPNOTSUPP;
   1360
   1361	if (args->pad != 0)
   1362		return -EINVAL;
   1363
   1364	if (args->count_handles == 0)
   1365		return -EINVAL;
   1366
   1367	ret = drm_syncobj_array_find(file_private,
   1368				     u64_to_user_ptr(args->handles),
   1369				     args->count_handles,
   1370				     &syncobjs);
   1371	if (ret < 0)
   1372		return ret;
   1373
   1374	for (i = 0; i < args->count_handles; i++)
   1375		drm_syncobj_replace_fence(syncobjs[i], NULL);
   1376
   1377	drm_syncobj_array_free(syncobjs, args->count_handles);
   1378
   1379	return 0;
   1380}
   1381
   1382int
   1383drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
   1384			 struct drm_file *file_private)
   1385{
   1386	struct drm_syncobj_array *args = data;
   1387	struct drm_syncobj **syncobjs;
   1388	uint32_t i;
   1389	int ret;
   1390
   1391	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
   1392		return -EOPNOTSUPP;
   1393
   1394	if (args->pad != 0)
   1395		return -EINVAL;
   1396
   1397	if (args->count_handles == 0)
   1398		return -EINVAL;
   1399
   1400	ret = drm_syncobj_array_find(file_private,
   1401				     u64_to_user_ptr(args->handles),
   1402				     args->count_handles,
   1403				     &syncobjs);
   1404	if (ret < 0)
   1405		return ret;
   1406
   1407	for (i = 0; i < args->count_handles; i++) {
   1408		ret = drm_syncobj_assign_null_handle(syncobjs[i]);
   1409		if (ret < 0)
   1410			break;
   1411	}
   1412
   1413	drm_syncobj_array_free(syncobjs, args->count_handles);
   1414
   1415	return ret;
   1416}
   1417
   1418int
   1419drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
   1420				  struct drm_file *file_private)
   1421{
   1422	struct drm_syncobj_timeline_array *args = data;
   1423	struct drm_syncobj **syncobjs;
   1424	struct dma_fence_chain **chains;
   1425	uint64_t *points;
   1426	uint32_t i, j;
   1427	int ret;
   1428
   1429	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
   1430		return -EOPNOTSUPP;
   1431
   1432	if (args->flags != 0)
   1433		return -EINVAL;
   1434
   1435	if (args->count_handles == 0)
   1436		return -EINVAL;
   1437
   1438	ret = drm_syncobj_array_find(file_private,
   1439				     u64_to_user_ptr(args->handles),
   1440				     args->count_handles,
   1441				     &syncobjs);
   1442	if (ret < 0)
   1443		return ret;
   1444
   1445	points = kmalloc_array(args->count_handles, sizeof(*points),
   1446			       GFP_KERNEL);
   1447	if (!points) {
   1448		ret = -ENOMEM;
   1449		goto out;
   1450	}
   1451	if (!u64_to_user_ptr(args->points)) {
   1452		memset(points, 0, args->count_handles * sizeof(uint64_t));
   1453	} else if (copy_from_user(points, u64_to_user_ptr(args->points),
   1454				  sizeof(uint64_t) * args->count_handles)) {
   1455		ret = -EFAULT;
   1456		goto err_points;
   1457	}
   1458
   1459	chains = kmalloc_array(args->count_handles, sizeof(void *), GFP_KERNEL);
   1460	if (!chains) {
   1461		ret = -ENOMEM;
   1462		goto err_points;
   1463	}
   1464	for (i = 0; i < args->count_handles; i++) {
   1465		chains[i] = dma_fence_chain_alloc();
   1466		if (!chains[i]) {
   1467			for (j = 0; j < i; j++)
   1468				dma_fence_chain_free(chains[j]);
   1469			ret = -ENOMEM;
   1470			goto err_chains;
   1471		}
   1472	}
   1473
   1474	for (i = 0; i < args->count_handles; i++) {
   1475		struct dma_fence *fence = dma_fence_get_stub();
   1476
   1477		drm_syncobj_add_point(syncobjs[i], chains[i],
   1478				      fence, points[i]);
   1479		dma_fence_put(fence);
   1480	}
   1481err_chains:
   1482	kfree(chains);
   1483err_points:
   1484	kfree(points);
   1485out:
   1486	drm_syncobj_array_free(syncobjs, args->count_handles);
   1487
   1488	return ret;
   1489}
   1490
   1491int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
   1492			    struct drm_file *file_private)
   1493{
   1494	struct drm_syncobj_timeline_array *args = data;
   1495	struct drm_syncobj **syncobjs;
   1496	uint64_t __user *points = u64_to_user_ptr(args->points);
   1497	uint32_t i;
   1498	int ret;
   1499
   1500	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
   1501		return -EOPNOTSUPP;
   1502
   1503	if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED)
   1504		return -EINVAL;
   1505
   1506	if (args->count_handles == 0)
   1507		return -EINVAL;
   1508
   1509	ret = drm_syncobj_array_find(file_private,
   1510				     u64_to_user_ptr(args->handles),
   1511				     args->count_handles,
   1512				     &syncobjs);
   1513	if (ret < 0)
   1514		return ret;
   1515
   1516	for (i = 0; i < args->count_handles; i++) {
   1517		struct dma_fence_chain *chain;
   1518		struct dma_fence *fence;
   1519		uint64_t point;
   1520
   1521		fence = drm_syncobj_fence_get(syncobjs[i]);
   1522		chain = to_dma_fence_chain(fence);
   1523		if (chain) {
   1524			struct dma_fence *iter, *last_signaled =
   1525				dma_fence_get(fence);
   1526
   1527			if (args->flags &
   1528			    DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) {
   1529				point = fence->seqno;
   1530			} else {
   1531				dma_fence_chain_for_each(iter, fence) {
   1532					if (iter->context != fence->context) {
   1533						dma_fence_put(iter);
   1534						/* It is most likely that timeline has
   1535						* unorder points. */
   1536						break;
   1537					}
   1538					dma_fence_put(last_signaled);
   1539					last_signaled = dma_fence_get(iter);
   1540				}
   1541				point = dma_fence_is_signaled(last_signaled) ?
   1542					last_signaled->seqno :
   1543					to_dma_fence_chain(last_signaled)->prev_seqno;
   1544			}
   1545			dma_fence_put(last_signaled);
   1546		} else {
   1547			point = 0;
   1548		}
   1549		dma_fence_put(fence);
   1550		ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
   1551		ret = ret ? -EFAULT : 0;
   1552		if (ret)
   1553			break;
   1554	}
   1555	drm_syncobj_array_free(syncobjs, args->count_handles);
   1556
   1557	return ret;
   1558}