root/drivers/gpu/drm/vgem/vgem_fence.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vgem_fence_get_driver_name
  2. vgem_fence_get_timeline_name
  3. vgem_fence_release
  4. vgem_fence_value_str
  5. vgem_fence_timeline_value_str
  6. vgem_fence_timeout
  7. vgem_fence_create
  8. vgem_fence_attach_ioctl
  9. vgem_fence_signal_ioctl
  10. vgem_fence_open
  11. __vgem_fence_idr_fini
  12. vgem_fence_close

   1 /*
   2  * Copyright 2016 Intel Corporation
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software")
   6  * to deal in the software without restriction, including without limitation
   7  * on the rights to use, copy, modify, merge, publish, distribute, sub
   8  * license, and/or sell copies of the Software, and to permit persons to whom
   9  * them Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice (including the next
  12  * paragraph) shall be included in all copies or substantial portions of the
  13  * Software.
  14  *
  15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
  17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
  18  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
  19  * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21  */
  22 
  23 #include <linux/dma-buf.h>
  24 #include <linux/dma-resv.h>
  25 
  26 #include <drm/drm_file.h>
  27 
  28 #include "vgem_drv.h"
  29 
  30 #define VGEM_FENCE_TIMEOUT (10*HZ)
  31 
  32 struct vgem_fence {
  33         struct dma_fence base;
  34         struct spinlock lock;
  35         struct timer_list timer;
  36 };
  37 
  38 static const char *vgem_fence_get_driver_name(struct dma_fence *fence)
  39 {
  40         return "vgem";
  41 }
  42 
  43 static const char *vgem_fence_get_timeline_name(struct dma_fence *fence)
  44 {
  45         return "unbound";
  46 }
  47 
  48 static void vgem_fence_release(struct dma_fence *base)
  49 {
  50         struct vgem_fence *fence = container_of(base, typeof(*fence), base);
  51 
  52         del_timer_sync(&fence->timer);
  53         dma_fence_free(&fence->base);
  54 }
  55 
  56 static void vgem_fence_value_str(struct dma_fence *fence, char *str, int size)
  57 {
  58         snprintf(str, size, "%llu", fence->seqno);
  59 }
  60 
  61 static void vgem_fence_timeline_value_str(struct dma_fence *fence, char *str,
  62                                           int size)
  63 {
  64         snprintf(str, size, "%llu",
  65                  dma_fence_is_signaled(fence) ? fence->seqno : 0);
  66 }
  67 
  68 static const struct dma_fence_ops vgem_fence_ops = {
  69         .get_driver_name = vgem_fence_get_driver_name,
  70         .get_timeline_name = vgem_fence_get_timeline_name,
  71         .release = vgem_fence_release,
  72 
  73         .fence_value_str = vgem_fence_value_str,
  74         .timeline_value_str = vgem_fence_timeline_value_str,
  75 };
  76 
  77 static void vgem_fence_timeout(struct timer_list *t)
  78 {
  79         struct vgem_fence *fence = from_timer(fence, t, timer);
  80 
  81         dma_fence_signal(&fence->base);
  82 }
  83 
  84 static struct dma_fence *vgem_fence_create(struct vgem_file *vfile,
  85                                            unsigned int flags)
  86 {
  87         struct vgem_fence *fence;
  88 
  89         fence = kzalloc(sizeof(*fence), GFP_KERNEL);
  90         if (!fence)
  91                 return NULL;
  92 
  93         spin_lock_init(&fence->lock);
  94         dma_fence_init(&fence->base, &vgem_fence_ops, &fence->lock,
  95                        dma_fence_context_alloc(1), 1);
  96 
  97         timer_setup(&fence->timer, vgem_fence_timeout, 0);
  98 
  99         /* We force the fence to expire within 10s to prevent driver hangs */
 100         mod_timer(&fence->timer, jiffies + VGEM_FENCE_TIMEOUT);
 101 
 102         return &fence->base;
 103 }
 104 
 105 /*
 106  * vgem_fence_attach_ioctl (DRM_IOCTL_VGEM_FENCE_ATTACH):
 107  *
 108  * Create and attach a fence to the vGEM handle. This fence is then exposed
 109  * via the dma-buf reservation object and visible to consumers of the exported
 110  * dma-buf. If the flags contain VGEM_FENCE_WRITE, the fence indicates the
 111  * vGEM buffer is being written to by the client and is exposed as an exclusive
 112  * fence, otherwise the fence indicates the client is current reading from the
 113  * buffer and all future writes should wait for the client to signal its
 114  * completion. Note that if a conflicting fence is already on the dma-buf (i.e.
 115  * an exclusive fence when adding a read, or any fence when adding a write),
 116  * -EBUSY is reported. Serialisation between operations should be handled
 117  * by waiting upon the dma-buf.
 118  *
 119  * This returns the handle for the new fence that must be signaled within 10
 120  * seconds (or otherwise it will automatically expire). See
 121  * vgem_fence_signal_ioctl (DRM_IOCTL_VGEM_FENCE_SIGNAL).
 122  *
 123  * If the vGEM handle does not exist, vgem_fence_attach_ioctl returns -ENOENT.
 124  */
 125 int vgem_fence_attach_ioctl(struct drm_device *dev,
 126                             void *data,
 127                             struct drm_file *file)
 128 {
 129         struct drm_vgem_fence_attach *arg = data;
 130         struct vgem_file *vfile = file->driver_priv;
 131         struct dma_resv *resv;
 132         struct drm_gem_object *obj;
 133         struct dma_fence *fence;
 134         int ret;
 135 
 136         if (arg->flags & ~VGEM_FENCE_WRITE)
 137                 return -EINVAL;
 138 
 139         if (arg->pad)
 140                 return -EINVAL;
 141 
 142         obj = drm_gem_object_lookup(file, arg->handle);
 143         if (!obj)
 144                 return -ENOENT;
 145 
 146         fence = vgem_fence_create(vfile, arg->flags);
 147         if (!fence) {
 148                 ret = -ENOMEM;
 149                 goto err;
 150         }
 151 
 152         /* Check for a conflicting fence */
 153         resv = obj->resv;
 154         if (!dma_resv_test_signaled_rcu(resv,
 155                                                   arg->flags & VGEM_FENCE_WRITE)) {
 156                 ret = -EBUSY;
 157                 goto err_fence;
 158         }
 159 
 160         /* Expose the fence via the dma-buf */
 161         ret = 0;
 162         dma_resv_lock(resv, NULL);
 163         if (arg->flags & VGEM_FENCE_WRITE)
 164                 dma_resv_add_excl_fence(resv, fence);
 165         else if ((ret = dma_resv_reserve_shared(resv, 1)) == 0)
 166                 dma_resv_add_shared_fence(resv, fence);
 167         dma_resv_unlock(resv);
 168 
 169         /* Record the fence in our idr for later signaling */
 170         if (ret == 0) {
 171                 mutex_lock(&vfile->fence_mutex);
 172                 ret = idr_alloc(&vfile->fence_idr, fence, 1, 0, GFP_KERNEL);
 173                 mutex_unlock(&vfile->fence_mutex);
 174                 if (ret > 0) {
 175                         arg->out_fence = ret;
 176                         ret = 0;
 177                 }
 178         }
 179 err_fence:
 180         if (ret) {
 181                 dma_fence_signal(fence);
 182                 dma_fence_put(fence);
 183         }
 184 err:
 185         drm_gem_object_put_unlocked(obj);
 186         return ret;
 187 }
 188 
 189 /*
 190  * vgem_fence_signal_ioctl (DRM_IOCTL_VGEM_FENCE_SIGNAL):
 191  *
 192  * Signal and consume a fence ealier attached to a vGEM handle using
 193  * vgem_fence_attach_ioctl (DRM_IOCTL_VGEM_FENCE_ATTACH).
 194  *
 195  * All fences must be signaled within 10s of attachment or otherwise they
 196  * will automatically expire (and a vgem_fence_signal_ioctl returns -ETIMEDOUT).
 197  *
 198  * Signaling a fence indicates to all consumers of the dma-buf that the
 199  * client has completed the operation associated with the fence, and that the
 200  * buffer is then ready for consumption.
 201  *
 202  * If the fence does not exist (or has already been signaled by the client),
 203  * vgem_fence_signal_ioctl returns -ENOENT.
 204  */
 205 int vgem_fence_signal_ioctl(struct drm_device *dev,
 206                             void *data,
 207                             struct drm_file *file)
 208 {
 209         struct vgem_file *vfile = file->driver_priv;
 210         struct drm_vgem_fence_signal *arg = data;
 211         struct dma_fence *fence;
 212         int ret = 0;
 213 
 214         if (arg->flags)
 215                 return -EINVAL;
 216 
 217         mutex_lock(&vfile->fence_mutex);
 218         fence = idr_replace(&vfile->fence_idr, NULL, arg->fence);
 219         mutex_unlock(&vfile->fence_mutex);
 220         if (!fence)
 221                 return -ENOENT;
 222         if (IS_ERR(fence))
 223                 return PTR_ERR(fence);
 224 
 225         if (dma_fence_is_signaled(fence))
 226                 ret = -ETIMEDOUT;
 227 
 228         dma_fence_signal(fence);
 229         dma_fence_put(fence);
 230         return ret;
 231 }
 232 
 233 int vgem_fence_open(struct vgem_file *vfile)
 234 {
 235         mutex_init(&vfile->fence_mutex);
 236         idr_init(&vfile->fence_idr);
 237 
 238         return 0;
 239 }
 240 
 241 static int __vgem_fence_idr_fini(int id, void *p, void *data)
 242 {
 243         dma_fence_signal(p);
 244         dma_fence_put(p);
 245         return 0;
 246 }
 247 
 248 void vgem_fence_close(struct vgem_file *vfile)
 249 {
 250         idr_for_each(&vfile->fence_idr, __vgem_fence_idr_fini, vfile);
 251         idr_destroy(&vfile->fence_idr);
 252 }

/* [<][>][^][v][top][bottom][index][help] */