2 * Copyright 2016 Intel Corporation
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:
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
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.
23 #include <linux/dma-buf.h>
24 #include <linux/reservation.h>
28 #define VGEM_FENCE_TIMEOUT (10*HZ)
31 struct dma_fence base
;
33 struct timer_list timer
;
36 static const char *vgem_fence_get_driver_name(struct dma_fence
*fence
)
41 static const char *vgem_fence_get_timeline_name(struct dma_fence
*fence
)
46 static bool vgem_fence_signaled(struct dma_fence
*fence
)
51 static bool vgem_fence_enable_signaling(struct dma_fence
*fence
)
56 static void vgem_fence_release(struct dma_fence
*base
)
58 struct vgem_fence
*fence
= container_of(base
, typeof(*fence
), base
);
60 del_timer_sync(&fence
->timer
);
61 dma_fence_free(&fence
->base
);
64 static void vgem_fence_value_str(struct dma_fence
*fence
, char *str
, int size
)
66 snprintf(str
, size
, "%u", fence
->seqno
);
69 static void vgem_fence_timeline_value_str(struct dma_fence
*fence
, char *str
,
72 snprintf(str
, size
, "%u",
73 dma_fence_is_signaled(fence
) ? fence
->seqno
: 0);
76 static const struct dma_fence_ops vgem_fence_ops
= {
77 .get_driver_name
= vgem_fence_get_driver_name
,
78 .get_timeline_name
= vgem_fence_get_timeline_name
,
79 .enable_signaling
= vgem_fence_enable_signaling
,
80 .signaled
= vgem_fence_signaled
,
81 .wait
= dma_fence_default_wait
,
82 .release
= vgem_fence_release
,
84 .fence_value_str
= vgem_fence_value_str
,
85 .timeline_value_str
= vgem_fence_timeline_value_str
,
88 static void vgem_fence_timeout(unsigned long data
)
90 struct vgem_fence
*fence
= (struct vgem_fence
*)data
;
92 dma_fence_signal(&fence
->base
);
95 static struct dma_fence
*vgem_fence_create(struct vgem_file
*vfile
,
98 struct vgem_fence
*fence
;
100 fence
= kzalloc(sizeof(*fence
), GFP_KERNEL
);
104 spin_lock_init(&fence
->lock
);
105 dma_fence_init(&fence
->base
, &vgem_fence_ops
, &fence
->lock
,
106 dma_fence_context_alloc(1), 1);
108 setup_timer(&fence
->timer
, vgem_fence_timeout
, (unsigned long)fence
);
110 /* We force the fence to expire within 10s to prevent driver hangs */
111 mod_timer(&fence
->timer
, jiffies
+ VGEM_FENCE_TIMEOUT
);
116 static int attach_dmabuf(struct drm_device
*dev
,
117 struct drm_gem_object
*obj
)
119 struct dma_buf
*dmabuf
;
124 dmabuf
= dev
->driver
->gem_prime_export(dev
, obj
, 0);
126 return PTR_ERR(dmabuf
);
128 obj
->dma_buf
= dmabuf
;
133 * vgem_fence_attach_ioctl (DRM_IOCTL_VGEM_FENCE_ATTACH):
135 * Create and attach a fence to the vGEM handle. This fence is then exposed
136 * via the dma-buf reservation object and visible to consumers of the exported
137 * dma-buf. If the flags contain VGEM_FENCE_WRITE, the fence indicates the
138 * vGEM buffer is being written to by the client and is exposed as an exclusive
139 * fence, otherwise the fence indicates the client is current reading from the
140 * buffer and all future writes should wait for the client to signal its
141 * completion. Note that if a conflicting fence is already on the dma-buf (i.e.
142 * an exclusive fence when adding a read, or any fence when adding a write),
143 * -EBUSY is reported. Serialisation between operations should be handled
144 * by waiting upon the dma-buf.
146 * This returns the handle for the new fence that must be signaled within 10
147 * seconds (or otherwise it will automatically expire). See
148 * vgem_fence_signal_ioctl (DRM_IOCTL_VGEM_FENCE_SIGNAL).
150 * If the vGEM handle does not exist, vgem_fence_attach_ioctl returns -ENOENT.
152 int vgem_fence_attach_ioctl(struct drm_device
*dev
,
154 struct drm_file
*file
)
156 struct drm_vgem_fence_attach
*arg
= data
;
157 struct vgem_file
*vfile
= file
->driver_priv
;
158 struct reservation_object
*resv
;
159 struct drm_gem_object
*obj
;
160 struct dma_fence
*fence
;
163 if (arg
->flags
& ~VGEM_FENCE_WRITE
)
169 obj
= drm_gem_object_lookup(file
, arg
->handle
);
173 ret
= attach_dmabuf(dev
, obj
);
177 fence
= vgem_fence_create(vfile
, arg
->flags
);
183 /* Check for a conflicting fence */
184 resv
= obj
->dma_buf
->resv
;
185 if (!reservation_object_test_signaled_rcu(resv
,
186 arg
->flags
& VGEM_FENCE_WRITE
)) {
191 /* Expose the fence via the dma-buf */
193 ww_mutex_lock(&resv
->lock
, NULL
);
194 if (arg
->flags
& VGEM_FENCE_WRITE
)
195 reservation_object_add_excl_fence(resv
, fence
);
196 else if ((ret
= reservation_object_reserve_shared(resv
)) == 0)
197 reservation_object_add_shared_fence(resv
, fence
);
198 ww_mutex_unlock(&resv
->lock
);
200 /* Record the fence in our idr for later signaling */
202 mutex_lock(&vfile
->fence_mutex
);
203 ret
= idr_alloc(&vfile
->fence_idr
, fence
, 1, 0, GFP_KERNEL
);
204 mutex_unlock(&vfile
->fence_mutex
);
206 arg
->out_fence
= ret
;
212 dma_fence_signal(fence
);
213 dma_fence_put(fence
);
216 drm_gem_object_unreference_unlocked(obj
);
221 * vgem_fence_signal_ioctl (DRM_IOCTL_VGEM_FENCE_SIGNAL):
223 * Signal and consume a fence ealier attached to a vGEM handle using
224 * vgem_fence_attach_ioctl (DRM_IOCTL_VGEM_FENCE_ATTACH).
226 * All fences must be signaled within 10s of attachment or otherwise they
227 * will automatically expire (and a vgem_fence_signal_ioctl returns -ETIMEDOUT).
229 * Signaling a fence indicates to all consumers of the dma-buf that the
230 * client has completed the operation associated with the fence, and that the
231 * buffer is then ready for consumption.
233 * If the fence does not exist (or has already been signaled by the client),
234 * vgem_fence_signal_ioctl returns -ENOENT.
236 int vgem_fence_signal_ioctl(struct drm_device
*dev
,
238 struct drm_file
*file
)
240 struct vgem_file
*vfile
= file
->driver_priv
;
241 struct drm_vgem_fence_signal
*arg
= data
;
242 struct dma_fence
*fence
;
248 mutex_lock(&vfile
->fence_mutex
);
249 fence
= idr_replace(&vfile
->fence_idr
, NULL
, arg
->fence
);
250 mutex_unlock(&vfile
->fence_mutex
);
254 return PTR_ERR(fence
);
256 if (dma_fence_is_signaled(fence
))
259 dma_fence_signal(fence
);
260 dma_fence_put(fence
);
264 int vgem_fence_open(struct vgem_file
*vfile
)
266 mutex_init(&vfile
->fence_mutex
);
267 idr_init(&vfile
->fence_idr
);
272 static int __vgem_fence_idr_fini(int id
, void *p
, void *data
)
279 void vgem_fence_close(struct vgem_file
*vfile
)
281 idr_for_each(&vfile
->fence_idr
, __vgem_fence_idr_fini
, vfile
);
282 idr_destroy(&vfile
->fence_idr
);