0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include <linux/dma-buf.h>
0024 #include <linux/dma-resv.h>
0025
0026 #include <drm/drm_file.h>
0027
0028 #include "vgem_drv.h"
0029
0030 #define VGEM_FENCE_TIMEOUT (10*HZ)
0031
0032 struct vgem_fence {
0033 struct dma_fence base;
0034 struct spinlock lock;
0035 struct timer_list timer;
0036 };
0037
0038 static const char *vgem_fence_get_driver_name(struct dma_fence *fence)
0039 {
0040 return "vgem";
0041 }
0042
0043 static const char *vgem_fence_get_timeline_name(struct dma_fence *fence)
0044 {
0045 return "unbound";
0046 }
0047
0048 static void vgem_fence_release(struct dma_fence *base)
0049 {
0050 struct vgem_fence *fence = container_of(base, typeof(*fence), base);
0051
0052 del_timer_sync(&fence->timer);
0053 dma_fence_free(&fence->base);
0054 }
0055
0056 static void vgem_fence_value_str(struct dma_fence *fence, char *str, int size)
0057 {
0058 snprintf(str, size, "%llu", fence->seqno);
0059 }
0060
0061 static void vgem_fence_timeline_value_str(struct dma_fence *fence, char *str,
0062 int size)
0063 {
0064 snprintf(str, size, "%llu",
0065 dma_fence_is_signaled(fence) ? fence->seqno : 0);
0066 }
0067
0068 static const struct dma_fence_ops vgem_fence_ops = {
0069 .get_driver_name = vgem_fence_get_driver_name,
0070 .get_timeline_name = vgem_fence_get_timeline_name,
0071 .release = vgem_fence_release,
0072
0073 .fence_value_str = vgem_fence_value_str,
0074 .timeline_value_str = vgem_fence_timeline_value_str,
0075 };
0076
0077 static void vgem_fence_timeout(struct timer_list *t)
0078 {
0079 struct vgem_fence *fence = from_timer(fence, t, timer);
0080
0081 dma_fence_signal(&fence->base);
0082 }
0083
0084 static struct dma_fence *vgem_fence_create(struct vgem_file *vfile,
0085 unsigned int flags)
0086 {
0087 struct vgem_fence *fence;
0088
0089 fence = kzalloc(sizeof(*fence), GFP_KERNEL);
0090 if (!fence)
0091 return NULL;
0092
0093 spin_lock_init(&fence->lock);
0094 dma_fence_init(&fence->base, &vgem_fence_ops, &fence->lock,
0095 dma_fence_context_alloc(1), 1);
0096
0097 timer_setup(&fence->timer, vgem_fence_timeout, 0);
0098
0099
0100 mod_timer(&fence->timer, jiffies + VGEM_FENCE_TIMEOUT);
0101
0102 return &fence->base;
0103 }
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125 int vgem_fence_attach_ioctl(struct drm_device *dev,
0126 void *data,
0127 struct drm_file *file)
0128 {
0129 struct drm_vgem_fence_attach *arg = data;
0130 struct vgem_file *vfile = file->driver_priv;
0131 struct dma_resv *resv;
0132 struct drm_gem_object *obj;
0133 enum dma_resv_usage usage;
0134 struct dma_fence *fence;
0135 int ret;
0136
0137 if (arg->flags & ~VGEM_FENCE_WRITE)
0138 return -EINVAL;
0139
0140 if (arg->pad)
0141 return -EINVAL;
0142
0143 obj = drm_gem_object_lookup(file, arg->handle);
0144 if (!obj)
0145 return -ENOENT;
0146
0147 fence = vgem_fence_create(vfile, arg->flags);
0148 if (!fence) {
0149 ret = -ENOMEM;
0150 goto err;
0151 }
0152
0153
0154 resv = obj->resv;
0155 usage = dma_resv_usage_rw(arg->flags & VGEM_FENCE_WRITE);
0156 if (!dma_resv_test_signaled(resv, usage)) {
0157 ret = -EBUSY;
0158 goto err_fence;
0159 }
0160
0161
0162 dma_resv_lock(resv, NULL);
0163 ret = dma_resv_reserve_fences(resv, 1);
0164 if (!ret)
0165 dma_resv_add_fence(resv, fence, arg->flags & VGEM_FENCE_WRITE ?
0166 DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ);
0167 dma_resv_unlock(resv);
0168
0169
0170 if (ret == 0) {
0171 mutex_lock(&vfile->fence_mutex);
0172 ret = idr_alloc(&vfile->fence_idr, fence, 1, 0, GFP_KERNEL);
0173 mutex_unlock(&vfile->fence_mutex);
0174 if (ret > 0) {
0175 arg->out_fence = ret;
0176 ret = 0;
0177 }
0178 }
0179 err_fence:
0180 if (ret) {
0181 dma_fence_signal(fence);
0182 dma_fence_put(fence);
0183 }
0184 err:
0185 drm_gem_object_put(obj);
0186 return ret;
0187 }
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205 int vgem_fence_signal_ioctl(struct drm_device *dev,
0206 void *data,
0207 struct drm_file *file)
0208 {
0209 struct vgem_file *vfile = file->driver_priv;
0210 struct drm_vgem_fence_signal *arg = data;
0211 struct dma_fence *fence;
0212 int ret = 0;
0213
0214 if (arg->flags)
0215 return -EINVAL;
0216
0217 mutex_lock(&vfile->fence_mutex);
0218 fence = idr_replace(&vfile->fence_idr, NULL, arg->fence);
0219 mutex_unlock(&vfile->fence_mutex);
0220 if (!fence)
0221 return -ENOENT;
0222 if (IS_ERR(fence))
0223 return PTR_ERR(fence);
0224
0225 if (dma_fence_is_signaled(fence))
0226 ret = -ETIMEDOUT;
0227
0228 dma_fence_signal(fence);
0229 dma_fence_put(fence);
0230 return ret;
0231 }
0232
0233 int vgem_fence_open(struct vgem_file *vfile)
0234 {
0235 mutex_init(&vfile->fence_mutex);
0236 idr_init_base(&vfile->fence_idr, 1);
0237
0238 return 0;
0239 }
0240
0241 static int __vgem_fence_idr_fini(int id, void *p, void *data)
0242 {
0243 dma_fence_signal(p);
0244 dma_fence_put(p);
0245 return 0;
0246 }
0247
0248 void vgem_fence_close(struct vgem_file *vfile)
0249 {
0250 idr_for_each(&vfile->fence_idr, __vgem_fence_idr_fini, vfile);
0251 idr_destroy(&vfile->fence_idr);
0252 }