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 void vgem_fence_release(struct dma_fence
*base
)
48 struct vgem_fence
*fence
= container_of(base
, typeof(*fence
), base
);
50 del_timer_sync(&fence
->timer
);
51 dma_fence_free(&fence
->base
);
54 static void vgem_fence_value_str(struct dma_fence
*fence
, char *str
, int size
)
56 snprintf(str
, size
, "%llu", fence
->seqno
);
59 static void vgem_fence_timeline_value_str(struct dma_fence
*fence
, char *str
,
62 snprintf(str
, size
, "%llu",
63 dma_fence_is_signaled(fence
) ? fence
->seqno
: 0);
66 static const struct dma_fence_ops vgem_fence_ops
= {
67 .get_driver_name
= vgem_fence_get_driver_name
,
68 .get_timeline_name
= vgem_fence_get_timeline_name
,
69 .release
= vgem_fence_release
,
71 .fence_value_str
= vgem_fence_value_str
,
72 .timeline_value_str
= vgem_fence_timeline_value_str
,
75 static void vgem_fence_timeout(struct timer_list
*t
)
77 struct vgem_fence
*fence
= from_timer(fence
, t
, timer
);
79 dma_fence_signal(&fence
->base
);
82 static struct dma_fence
*vgem_fence_create(struct vgem_file
*vfile
,
85 struct vgem_fence
*fence
;
87 fence
= kzalloc(sizeof(*fence
), GFP_KERNEL
);
91 spin_lock_init(&fence
->lock
);
92 dma_fence_init(&fence
->base
, &vgem_fence_ops
, &fence
->lock
,
93 dma_fence_context_alloc(1), 1);
95 timer_setup(&fence
->timer
, vgem_fence_timeout
, 0);
97 /* We force the fence to expire within 10s to prevent driver hangs */
98 mod_timer(&fence
->timer
, jiffies
+ VGEM_FENCE_TIMEOUT
);
103 static int attach_dmabuf(struct drm_device
*dev
,
104 struct drm_gem_object
*obj
)
106 struct dma_buf
*dmabuf
;
111 dmabuf
= dev
->driver
->gem_prime_export(dev
, obj
, 0);
113 return PTR_ERR(dmabuf
);
115 obj
->dma_buf
= dmabuf
;
120 * vgem_fence_attach_ioctl (DRM_IOCTL_VGEM_FENCE_ATTACH):
122 * Create and attach a fence to the vGEM handle. This fence is then exposed
123 * via the dma-buf reservation object and visible to consumers of the exported
124 * dma-buf. If the flags contain VGEM_FENCE_WRITE, the fence indicates the
125 * vGEM buffer is being written to by the client and is exposed as an exclusive
126 * fence, otherwise the fence indicates the client is current reading from the
127 * buffer and all future writes should wait for the client to signal its
128 * completion. Note that if a conflicting fence is already on the dma-buf (i.e.
129 * an exclusive fence when adding a read, or any fence when adding a write),
130 * -EBUSY is reported. Serialisation between operations should be handled
131 * by waiting upon the dma-buf.
133 * This returns the handle for the new fence that must be signaled within 10
134 * seconds (or otherwise it will automatically expire). See
135 * vgem_fence_signal_ioctl (DRM_IOCTL_VGEM_FENCE_SIGNAL).
137 * If the vGEM handle does not exist, vgem_fence_attach_ioctl returns -ENOENT.
139 int vgem_fence_attach_ioctl(struct drm_device
*dev
,
141 struct drm_file
*file
)
143 struct drm_vgem_fence_attach
*arg
= data
;
144 struct vgem_file
*vfile
= file
->driver_priv
;
145 struct reservation_object
*resv
;
146 struct drm_gem_object
*obj
;
147 struct dma_fence
*fence
;
150 if (arg
->flags
& ~VGEM_FENCE_WRITE
)
156 obj
= drm_gem_object_lookup(file
, arg
->handle
);
160 ret
= attach_dmabuf(dev
, obj
);
164 fence
= vgem_fence_create(vfile
, arg
->flags
);
170 /* Check for a conflicting fence */
171 resv
= obj
->dma_buf
->resv
;
172 if (!reservation_object_test_signaled_rcu(resv
,
173 arg
->flags
& VGEM_FENCE_WRITE
)) {
178 /* Expose the fence via the dma-buf */
180 reservation_object_lock(resv
, NULL
);
181 if (arg
->flags
& VGEM_FENCE_WRITE
)
182 reservation_object_add_excl_fence(resv
, fence
);
183 else if ((ret
= reservation_object_reserve_shared(resv
, 1)) == 0)
184 reservation_object_add_shared_fence(resv
, fence
);
185 reservation_object_unlock(resv
);
187 /* Record the fence in our idr for later signaling */
189 mutex_lock(&vfile
->fence_mutex
);
190 ret
= idr_alloc(&vfile
->fence_idr
, fence
, 1, 0, GFP_KERNEL
);
191 mutex_unlock(&vfile
->fence_mutex
);
193 arg
->out_fence
= ret
;
199 dma_fence_signal(fence
);
200 dma_fence_put(fence
);
203 drm_gem_object_put_unlocked(obj
);
208 * vgem_fence_signal_ioctl (DRM_IOCTL_VGEM_FENCE_SIGNAL):
210 * Signal and consume a fence ealier attached to a vGEM handle using
211 * vgem_fence_attach_ioctl (DRM_IOCTL_VGEM_FENCE_ATTACH).
213 * All fences must be signaled within 10s of attachment or otherwise they
214 * will automatically expire (and a vgem_fence_signal_ioctl returns -ETIMEDOUT).
216 * Signaling a fence indicates to all consumers of the dma-buf that the
217 * client has completed the operation associated with the fence, and that the
218 * buffer is then ready for consumption.
220 * If the fence does not exist (or has already been signaled by the client),
221 * vgem_fence_signal_ioctl returns -ENOENT.
223 int vgem_fence_signal_ioctl(struct drm_device
*dev
,
225 struct drm_file
*file
)
227 struct vgem_file
*vfile
= file
->driver_priv
;
228 struct drm_vgem_fence_signal
*arg
= data
;
229 struct dma_fence
*fence
;
235 mutex_lock(&vfile
->fence_mutex
);
236 fence
= idr_replace(&vfile
->fence_idr
, NULL
, arg
->fence
);
237 mutex_unlock(&vfile
->fence_mutex
);
241 return PTR_ERR(fence
);
243 if (dma_fence_is_signaled(fence
))
246 dma_fence_signal(fence
);
247 dma_fence_put(fence
);
251 int vgem_fence_open(struct vgem_file
*vfile
)
253 mutex_init(&vfile
->fence_mutex
);
254 idr_init(&vfile
->fence_idr
);
259 static int __vgem_fence_idr_fini(int id
, void *p
, void *data
)
266 void vgem_fence_close(struct vgem_file
*vfile
)
268 idr_for_each(&vfile
->fence_idr
, __vgem_fence_idr_fini
, vfile
);
269 idr_destroy(&vfile
->fence_idr
);