0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/file.h>
0009 #include <linux/fs.h>
0010 #include <linux/uaccess.h>
0011 #include <linux/slab.h>
0012 #include <linux/sync_file.h>
0013
0014 #include "sync_debug.h"
0015
0016 #define CREATE_TRACE_POINTS
0017 #include "sync_trace.h"
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 struct sw_sync_create_fence_data {
0050 __u32 value;
0051 char name[32];
0052 __s32 fence;
0053 };
0054
0055 #define SW_SYNC_IOC_MAGIC 'W'
0056
0057 #define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
0058 struct sw_sync_create_fence_data)
0059
0060 #define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
0061
0062 static const struct dma_fence_ops timeline_fence_ops;
0063
0064 static inline struct sync_pt *dma_fence_to_sync_pt(struct dma_fence *fence)
0065 {
0066 if (fence->ops != &timeline_fence_ops)
0067 return NULL;
0068 return container_of(fence, struct sync_pt, base);
0069 }
0070
0071
0072
0073
0074
0075
0076
0077
0078 static struct sync_timeline *sync_timeline_create(const char *name)
0079 {
0080 struct sync_timeline *obj;
0081
0082 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
0083 if (!obj)
0084 return NULL;
0085
0086 kref_init(&obj->kref);
0087 obj->context = dma_fence_context_alloc(1);
0088 strlcpy(obj->name, name, sizeof(obj->name));
0089
0090 obj->pt_tree = RB_ROOT;
0091 INIT_LIST_HEAD(&obj->pt_list);
0092 spin_lock_init(&obj->lock);
0093
0094 sync_timeline_debug_add(obj);
0095
0096 return obj;
0097 }
0098
0099 static void sync_timeline_free(struct kref *kref)
0100 {
0101 struct sync_timeline *obj =
0102 container_of(kref, struct sync_timeline, kref);
0103
0104 sync_timeline_debug_remove(obj);
0105
0106 kfree(obj);
0107 }
0108
0109 static void sync_timeline_get(struct sync_timeline *obj)
0110 {
0111 kref_get(&obj->kref);
0112 }
0113
0114 static void sync_timeline_put(struct sync_timeline *obj)
0115 {
0116 kref_put(&obj->kref, sync_timeline_free);
0117 }
0118
0119 static const char *timeline_fence_get_driver_name(struct dma_fence *fence)
0120 {
0121 return "sw_sync";
0122 }
0123
0124 static const char *timeline_fence_get_timeline_name(struct dma_fence *fence)
0125 {
0126 struct sync_timeline *parent = dma_fence_parent(fence);
0127
0128 return parent->name;
0129 }
0130
0131 static void timeline_fence_release(struct dma_fence *fence)
0132 {
0133 struct sync_pt *pt = dma_fence_to_sync_pt(fence);
0134 struct sync_timeline *parent = dma_fence_parent(fence);
0135 unsigned long flags;
0136
0137 spin_lock_irqsave(fence->lock, flags);
0138 if (!list_empty(&pt->link)) {
0139 list_del(&pt->link);
0140 rb_erase(&pt->node, &parent->pt_tree);
0141 }
0142 spin_unlock_irqrestore(fence->lock, flags);
0143
0144 sync_timeline_put(parent);
0145 dma_fence_free(fence);
0146 }
0147
0148 static bool timeline_fence_signaled(struct dma_fence *fence)
0149 {
0150 struct sync_timeline *parent = dma_fence_parent(fence);
0151
0152 return !__dma_fence_is_later(fence->seqno, parent->value, fence->ops);
0153 }
0154
0155 static bool timeline_fence_enable_signaling(struct dma_fence *fence)
0156 {
0157 return true;
0158 }
0159
0160 static void timeline_fence_value_str(struct dma_fence *fence,
0161 char *str, int size)
0162 {
0163 snprintf(str, size, "%lld", fence->seqno);
0164 }
0165
0166 static void timeline_fence_timeline_value_str(struct dma_fence *fence,
0167 char *str, int size)
0168 {
0169 struct sync_timeline *parent = dma_fence_parent(fence);
0170
0171 snprintf(str, size, "%d", parent->value);
0172 }
0173
0174 static const struct dma_fence_ops timeline_fence_ops = {
0175 .get_driver_name = timeline_fence_get_driver_name,
0176 .get_timeline_name = timeline_fence_get_timeline_name,
0177 .enable_signaling = timeline_fence_enable_signaling,
0178 .signaled = timeline_fence_signaled,
0179 .release = timeline_fence_release,
0180 .fence_value_str = timeline_fence_value_str,
0181 .timeline_value_str = timeline_fence_timeline_value_str,
0182 };
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
0193 {
0194 struct sync_pt *pt, *next;
0195
0196 trace_sync_timeline(obj);
0197
0198 spin_lock_irq(&obj->lock);
0199
0200 obj->value += inc;
0201
0202 list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
0203 if (!timeline_fence_signaled(&pt->base))
0204 break;
0205
0206 list_del_init(&pt->link);
0207 rb_erase(&pt->node, &obj->pt_tree);
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 dma_fence_signal_locked(&pt->base);
0218 }
0219
0220 spin_unlock_irq(&obj->lock);
0221 }
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233 static struct sync_pt *sync_pt_create(struct sync_timeline *obj,
0234 unsigned int value)
0235 {
0236 struct sync_pt *pt;
0237
0238 pt = kzalloc(sizeof(*pt), GFP_KERNEL);
0239 if (!pt)
0240 return NULL;
0241
0242 sync_timeline_get(obj);
0243 dma_fence_init(&pt->base, &timeline_fence_ops, &obj->lock,
0244 obj->context, value);
0245 INIT_LIST_HEAD(&pt->link);
0246
0247 spin_lock_irq(&obj->lock);
0248 if (!dma_fence_is_signaled_locked(&pt->base)) {
0249 struct rb_node **p = &obj->pt_tree.rb_node;
0250 struct rb_node *parent = NULL;
0251
0252 while (*p) {
0253 struct sync_pt *other;
0254 int cmp;
0255
0256 parent = *p;
0257 other = rb_entry(parent, typeof(*pt), node);
0258 cmp = value - other->base.seqno;
0259 if (cmp > 0) {
0260 p = &parent->rb_right;
0261 } else if (cmp < 0) {
0262 p = &parent->rb_left;
0263 } else {
0264 if (dma_fence_get_rcu(&other->base)) {
0265 sync_timeline_put(obj);
0266 kfree(pt);
0267 pt = other;
0268 goto unlock;
0269 }
0270 p = &parent->rb_left;
0271 }
0272 }
0273 rb_link_node(&pt->node, parent, p);
0274 rb_insert_color(&pt->node, &obj->pt_tree);
0275
0276 parent = rb_next(&pt->node);
0277 list_add_tail(&pt->link,
0278 parent ? &rb_entry(parent, typeof(*pt), node)->link : &obj->pt_list);
0279 }
0280 unlock:
0281 spin_unlock_irq(&obj->lock);
0282
0283 return pt;
0284 }
0285
0286
0287
0288
0289
0290
0291
0292
0293 static int sw_sync_debugfs_open(struct inode *inode, struct file *file)
0294 {
0295 struct sync_timeline *obj;
0296 char task_comm[TASK_COMM_LEN];
0297
0298 get_task_comm(task_comm, current);
0299
0300 obj = sync_timeline_create(task_comm);
0301 if (!obj)
0302 return -ENOMEM;
0303
0304 file->private_data = obj;
0305
0306 return 0;
0307 }
0308
0309 static int sw_sync_debugfs_release(struct inode *inode, struct file *file)
0310 {
0311 struct sync_timeline *obj = file->private_data;
0312 struct sync_pt *pt, *next;
0313
0314 spin_lock_irq(&obj->lock);
0315
0316 list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
0317 dma_fence_set_error(&pt->base, -ENOENT);
0318 dma_fence_signal_locked(&pt->base);
0319 }
0320
0321 spin_unlock_irq(&obj->lock);
0322
0323 sync_timeline_put(obj);
0324 return 0;
0325 }
0326
0327 static long sw_sync_ioctl_create_fence(struct sync_timeline *obj,
0328 unsigned long arg)
0329 {
0330 int fd = get_unused_fd_flags(O_CLOEXEC);
0331 int err;
0332 struct sync_pt *pt;
0333 struct sync_file *sync_file;
0334 struct sw_sync_create_fence_data data;
0335
0336 if (fd < 0)
0337 return fd;
0338
0339 if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
0340 err = -EFAULT;
0341 goto err;
0342 }
0343
0344 pt = sync_pt_create(obj, data.value);
0345 if (!pt) {
0346 err = -ENOMEM;
0347 goto err;
0348 }
0349
0350 sync_file = sync_file_create(&pt->base);
0351 dma_fence_put(&pt->base);
0352 if (!sync_file) {
0353 err = -ENOMEM;
0354 goto err;
0355 }
0356
0357 data.fence = fd;
0358 if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
0359 fput(sync_file->file);
0360 err = -EFAULT;
0361 goto err;
0362 }
0363
0364 fd_install(fd, sync_file->file);
0365
0366 return 0;
0367
0368 err:
0369 put_unused_fd(fd);
0370 return err;
0371 }
0372
0373 static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg)
0374 {
0375 u32 value;
0376
0377 if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
0378 return -EFAULT;
0379
0380 while (value > INT_MAX) {
0381 sync_timeline_signal(obj, INT_MAX);
0382 value -= INT_MAX;
0383 }
0384
0385 sync_timeline_signal(obj, value);
0386
0387 return 0;
0388 }
0389
0390 static long sw_sync_ioctl(struct file *file, unsigned int cmd,
0391 unsigned long arg)
0392 {
0393 struct sync_timeline *obj = file->private_data;
0394
0395 switch (cmd) {
0396 case SW_SYNC_IOC_CREATE_FENCE:
0397 return sw_sync_ioctl_create_fence(obj, arg);
0398
0399 case SW_SYNC_IOC_INC:
0400 return sw_sync_ioctl_inc(obj, arg);
0401
0402 default:
0403 return -ENOTTY;
0404 }
0405 }
0406
0407 const struct file_operations sw_sync_debugfs_fops = {
0408 .open = sw_sync_debugfs_open,
0409 .release = sw_sync_debugfs_release,
0410 .unlocked_ioctl = sw_sync_ioctl,
0411 .compat_ioctl = compat_ptr_ioctl,
0412 };