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/dma-resv.h>
26 #include <drm/drm_file.h>
30 #define VGEM_FENCE_TIMEOUT (10*HZ)
33 struct dma_fence base
;
35 struct timer_list timer
;
38 static const char *vgem_fence_get_driver_name(struct dma_fence
*fence
)
43 static const char *vgem_fence_get_timeline_name(struct dma_fence
*fence
)
48 static void vgem_fence_release(struct dma_fence
*base
)
50 struct vgem_fence
*fence
= container_of(base
, typeof(*fence
), base
);
52 del_timer_sync(&fence
->timer
);
53 dma_fence_free(&fence
->base
);
56 static void vgem_fence_value_str(struct dma_fence
*fence
, char *str
, int size
)
58 snprintf(str
, size
, "%llu", fence
->seqno
);
61 static void vgem_fence_timeline_value_str(struct dma_fence
*fence
, char *str
,
64 snprintf(str
, size
, "%llu",
65 dma_fence_is_signaled(fence
) ? fence
->seqno
: 0);
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
,
73 .fence_value_str
= vgem_fence_value_str
,
74 .timeline_value_str
= vgem_fence_timeline_value_str
,
77 static void vgem_fence_timeout(struct timer_list
*t
)
79 struct vgem_fence
*fence
= from_timer(fence
, t
, timer
);
81 dma_fence_signal(&fence
->base
);
84 static struct dma_fence
*vgem_fence_create(struct vgem_file
*vfile
,
87 struct vgem_fence
*fence
;
89 fence
= kzalloc(sizeof(*fence
), GFP_KERNEL
);
93 spin_lock_init(&fence
->lock
);
94 dma_fence_init(&fence
->base
, &vgem_fence_ops
, &fence
->lock
,
95 dma_fence_context_alloc(1), 1);
97 timer_setup(&fence
->timer
, vgem_fence_timeout
, 0);
99 /* We force the fence to expire within 10s to prevent driver hangs */
100 mod_timer(&fence
->timer
, jiffies
+ VGEM_FENCE_TIMEOUT
);
106 * vgem_fence_attach_ioctl (DRM_IOCTL_VGEM_FENCE_ATTACH):
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.
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).
123 * If the vGEM handle does not exist, vgem_fence_attach_ioctl returns -ENOENT.
125 int vgem_fence_attach_ioctl(struct drm_device
*dev
,
127 struct drm_file
*file
)
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
;
136 if (arg
->flags
& ~VGEM_FENCE_WRITE
)
142 obj
= drm_gem_object_lookup(file
, arg
->handle
);
146 fence
= vgem_fence_create(vfile
, arg
->flags
);
152 /* Check for a conflicting fence */
154 if (!dma_resv_test_signaled_rcu(resv
,
155 arg
->flags
& VGEM_FENCE_WRITE
)) {
160 /* Expose the fence via the dma-buf */
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
);
169 /* Record the fence in our idr for later signaling */
171 mutex_lock(&vfile
->fence_mutex
);
172 ret
= idr_alloc(&vfile
->fence_idr
, fence
, 1, 0, GFP_KERNEL
);
173 mutex_unlock(&vfile
->fence_mutex
);
175 arg
->out_fence
= ret
;
181 dma_fence_signal(fence
);
182 dma_fence_put(fence
);
185 drm_gem_object_put(obj
);
190 * vgem_fence_signal_ioctl (DRM_IOCTL_VGEM_FENCE_SIGNAL):
192 * Signal and consume a fence ealier attached to a vGEM handle using
193 * vgem_fence_attach_ioctl (DRM_IOCTL_VGEM_FENCE_ATTACH).
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).
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.
202 * If the fence does not exist (or has already been signaled by the client),
203 * vgem_fence_signal_ioctl returns -ENOENT.
205 int vgem_fence_signal_ioctl(struct drm_device
*dev
,
207 struct drm_file
*file
)
209 struct vgem_file
*vfile
= file
->driver_priv
;
210 struct drm_vgem_fence_signal
*arg
= data
;
211 struct dma_fence
*fence
;
217 mutex_lock(&vfile
->fence_mutex
);
218 fence
= idr_replace(&vfile
->fence_idr
, NULL
, arg
->fence
);
219 mutex_unlock(&vfile
->fence_mutex
);
223 return PTR_ERR(fence
);
225 if (dma_fence_is_signaled(fence
))
228 dma_fence_signal(fence
);
229 dma_fence_put(fence
);
233 int vgem_fence_open(struct vgem_file
*vfile
)
235 mutex_init(&vfile
->fence_mutex
);
236 idr_init_base(&vfile
->fence_idr
, 1);
241 static int __vgem_fence_idr_fini(int id
, void *p
, void *data
)
248 void vgem_fence_close(struct vgem_file
*vfile
)
250 idr_for_each(&vfile
->fence_idr
, __vgem_fence_idr_fini
, vfile
);
251 idr_destroy(&vfile
->fence_idr
);