LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_syncobj.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 583 0.0 %
Date: 2022-03-28 16:04:14 Functions: 0 40 0.0 %
Branches: 0 308 0.0 %

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

Generated by: LCOV version 1.14