linux/drivers/staging/android/sync.c
<<
>>
Prefs
   1/*
   2 * drivers/base/sync.c
   3 *
   4 * Copyright (C) 2012 Google, Inc.
   5 *
   6 * This software is licensed under the terms of the GNU General Public
   7 * License version 2, as published by the Free Software Foundation, and
   8 * may be copied, distributed, and modified under those terms.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 */
  16
  17#include <linux/debugfs.h>
  18#include <linux/export.h>
  19#include <linux/file.h>
  20#include <linux/fs.h>
  21#include <linux/kernel.h>
  22#include <linux/poll.h>
  23#include <linux/sched.h>
  24#include <linux/seq_file.h>
  25#include <linux/slab.h>
  26#include <linux/uaccess.h>
  27#include <linux/anon_inodes.h>
  28
  29#include "sync.h"
  30
  31#define CREATE_TRACE_POINTS
  32#include "trace/sync.h"
  33
  34static const struct fence_ops android_fence_ops;
  35static const struct file_operations sync_file_fops;
  36
  37struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
  38                                           int size, const char *name)
  39{
  40        struct sync_timeline *obj;
  41
  42        if (size < sizeof(struct sync_timeline))
  43                return NULL;
  44
  45        obj = kzalloc(size, GFP_KERNEL);
  46        if (!obj)
  47                return NULL;
  48
  49        kref_init(&obj->kref);
  50        obj->ops = ops;
  51        obj->context = fence_context_alloc(1);
  52        strlcpy(obj->name, name, sizeof(obj->name));
  53
  54        INIT_LIST_HEAD(&obj->child_list_head);
  55        INIT_LIST_HEAD(&obj->active_list_head);
  56        spin_lock_init(&obj->child_list_lock);
  57
  58        sync_timeline_debug_add(obj);
  59
  60        return obj;
  61}
  62EXPORT_SYMBOL(sync_timeline_create);
  63
  64static void sync_timeline_free(struct kref *kref)
  65{
  66        struct sync_timeline *obj =
  67                container_of(kref, struct sync_timeline, kref);
  68
  69        sync_timeline_debug_remove(obj);
  70
  71        kfree(obj);
  72}
  73
  74static void sync_timeline_get(struct sync_timeline *obj)
  75{
  76        kref_get(&obj->kref);
  77}
  78
  79static void sync_timeline_put(struct sync_timeline *obj)
  80{
  81        kref_put(&obj->kref, sync_timeline_free);
  82}
  83
  84void sync_timeline_destroy(struct sync_timeline *obj)
  85{
  86        obj->destroyed = true;
  87        /*
  88         * Ensure timeline is marked as destroyed before
  89         * changing timeline's fences status.
  90         */
  91        smp_wmb();
  92
  93        sync_timeline_put(obj);
  94}
  95EXPORT_SYMBOL(sync_timeline_destroy);
  96
  97void sync_timeline_signal(struct sync_timeline *obj)
  98{
  99        unsigned long flags;
 100        struct fence *fence, *next;
 101
 102        trace_sync_timeline(obj);
 103
 104        spin_lock_irqsave(&obj->child_list_lock, flags);
 105
 106        list_for_each_entry_safe(fence, next, &obj->active_list_head,
 107                                 active_list) {
 108                if (fence_is_signaled_locked(fence))
 109                        list_del_init(&fence->active_list);
 110        }
 111
 112        spin_unlock_irqrestore(&obj->child_list_lock, flags);
 113}
 114EXPORT_SYMBOL(sync_timeline_signal);
 115
 116struct fence *sync_pt_create(struct sync_timeline *obj, int size)
 117{
 118        unsigned long flags;
 119        struct fence *fence;
 120
 121        if (size < sizeof(*fence))
 122                return NULL;
 123
 124        fence = kzalloc(size, GFP_KERNEL);
 125        if (!fence)
 126                return NULL;
 127
 128        spin_lock_irqsave(&obj->child_list_lock, flags);
 129        sync_timeline_get(obj);
 130        fence_init(fence, &android_fence_ops, &obj->child_list_lock,
 131                   obj->context, ++obj->value);
 132        list_add_tail(&fence->child_list, &obj->child_list_head);
 133        INIT_LIST_HEAD(&fence->active_list);
 134        spin_unlock_irqrestore(&obj->child_list_lock, flags);
 135        return fence;
 136}
 137EXPORT_SYMBOL(sync_pt_create);
 138
 139static struct sync_file *sync_file_alloc(int size, const char *name)
 140{
 141        struct sync_file *sync_file;
 142
 143        sync_file = kzalloc(size, GFP_KERNEL);
 144        if (!sync_file)
 145                return NULL;
 146
 147        sync_file->file = anon_inode_getfile("sync_file", &sync_file_fops,
 148                                             sync_file, 0);
 149        if (IS_ERR(sync_file->file))
 150                goto err;
 151
 152        kref_init(&sync_file->kref);
 153        strlcpy(sync_file->name, name, sizeof(sync_file->name));
 154
 155        init_waitqueue_head(&sync_file->wq);
 156
 157        return sync_file;
 158
 159err:
 160        kfree(sync_file);
 161        return NULL;
 162}
 163
 164static void fence_check_cb_func(struct fence *f, struct fence_cb *cb)
 165{
 166        struct sync_file_cb *check;
 167        struct sync_file *sync_file;
 168
 169        check = container_of(cb, struct sync_file_cb, cb);
 170        sync_file = check->sync_file;
 171
 172        if (atomic_dec_and_test(&sync_file->status))
 173                wake_up_all(&sync_file->wq);
 174}
 175
 176/* TODO: implement a create which takes more that one fence */
 177struct sync_file *sync_file_create(const char *name, struct fence *fence)
 178{
 179        struct sync_file *sync_file;
 180
 181        sync_file = sync_file_alloc(offsetof(struct sync_file, cbs[1]),
 182                                    name);
 183        if (!sync_file)
 184                return NULL;
 185
 186        sync_file->num_fences = 1;
 187        atomic_set(&sync_file->status, 1);
 188
 189        sync_file->cbs[0].fence = fence;
 190        sync_file->cbs[0].sync_file = sync_file;
 191        if (fence_add_callback(fence, &sync_file->cbs[0].cb,
 192                               fence_check_cb_func))
 193                atomic_dec(&sync_file->status);
 194
 195        sync_file_debug_add(sync_file);
 196
 197        return sync_file;
 198}
 199EXPORT_SYMBOL(sync_file_create);
 200
 201struct sync_file *sync_file_fdget(int fd)
 202{
 203        struct file *file = fget(fd);
 204
 205        if (!file)
 206                return NULL;
 207
 208        if (file->f_op != &sync_file_fops)
 209                goto err;
 210
 211        return file->private_data;
 212
 213err:
 214        fput(file);
 215        return NULL;
 216}
 217EXPORT_SYMBOL(sync_file_fdget);
 218
 219void sync_file_put(struct sync_file *sync_file)
 220{
 221        fput(sync_file->file);
 222}
 223EXPORT_SYMBOL(sync_file_put);
 224
 225void sync_file_install(struct sync_file *sync_file, int fd)
 226{
 227        fd_install(fd, sync_file->file);
 228}
 229EXPORT_SYMBOL(sync_file_install);
 230
 231static void sync_file_add_pt(struct sync_file *sync_file, int *i,
 232                             struct fence *fence)
 233{
 234        sync_file->cbs[*i].fence = fence;
 235        sync_file->cbs[*i].sync_file = sync_file;
 236
 237        if (!fence_add_callback(fence, &sync_file->cbs[*i].cb,
 238                                fence_check_cb_func)) {
 239                fence_get(fence);
 240                (*i)++;
 241        }
 242}
 243
 244struct sync_file *sync_file_merge(const char *name,
 245                                  struct sync_file *a, struct sync_file *b)
 246{
 247        int num_fences = a->num_fences + b->num_fences;
 248        struct sync_file *sync_file;
 249        int i, i_a, i_b;
 250        unsigned long size = offsetof(struct sync_file, cbs[num_fences]);
 251
 252        sync_file = sync_file_alloc(size, name);
 253        if (!sync_file)
 254                return NULL;
 255
 256        atomic_set(&sync_file->status, num_fences);
 257
 258        /*
 259         * Assume sync_file a and b are both ordered and have no
 260         * duplicates with the same context.
 261         *
 262         * If a sync_file can only be created with sync_file_merge
 263         * and sync_file_create, this is a reasonable assumption.
 264         */
 265        for (i = i_a = i_b = 0; i_a < a->num_fences && i_b < b->num_fences; ) {
 266                struct fence *pt_a = a->cbs[i_a].fence;
 267                struct fence *pt_b = b->cbs[i_b].fence;
 268
 269                if (pt_a->context < pt_b->context) {
 270                        sync_file_add_pt(sync_file, &i, pt_a);
 271
 272                        i_a++;
 273                } else if (pt_a->context > pt_b->context) {
 274                        sync_file_add_pt(sync_file, &i, pt_b);
 275
 276                        i_b++;
 277                } else {
 278                        if (pt_a->seqno - pt_b->seqno <= INT_MAX)
 279                                sync_file_add_pt(sync_file, &i, pt_a);
 280                        else
 281                                sync_file_add_pt(sync_file, &i, pt_b);
 282
 283                        i_a++;
 284                        i_b++;
 285                }
 286        }
 287
 288        for (; i_a < a->num_fences; i_a++)
 289                sync_file_add_pt(sync_file, &i, a->cbs[i_a].fence);
 290
 291        for (; i_b < b->num_fences; i_b++)
 292                sync_file_add_pt(sync_file, &i, b->cbs[i_b].fence);
 293
 294        if (num_fences > i)
 295                atomic_sub(num_fences - i, &sync_file->status);
 296        sync_file->num_fences = i;
 297
 298        sync_file_debug_add(sync_file);
 299        return sync_file;
 300}
 301EXPORT_SYMBOL(sync_file_merge);
 302
 303static const char *android_fence_get_driver_name(struct fence *fence)
 304{
 305        struct sync_timeline *parent = fence_parent(fence);
 306
 307        return parent->ops->driver_name;
 308}
 309
 310static const char *android_fence_get_timeline_name(struct fence *fence)
 311{
 312        struct sync_timeline *parent = fence_parent(fence);
 313
 314        return parent->name;
 315}
 316
 317static void android_fence_release(struct fence *fence)
 318{
 319        struct sync_timeline *parent = fence_parent(fence);
 320        unsigned long flags;
 321
 322        spin_lock_irqsave(fence->lock, flags);
 323        list_del(&fence->child_list);
 324        if (WARN_ON_ONCE(!list_empty(&fence->active_list)))
 325                list_del(&fence->active_list);
 326        spin_unlock_irqrestore(fence->lock, flags);
 327
 328        sync_timeline_put(parent);
 329        fence_free(fence);
 330}
 331
 332static bool android_fence_signaled(struct fence *fence)
 333{
 334        struct sync_timeline *parent = fence_parent(fence);
 335        int ret;
 336
 337        ret = parent->ops->has_signaled(fence);
 338        if (ret < 0)
 339                fence->status = ret;
 340        return ret;
 341}
 342
 343static bool android_fence_enable_signaling(struct fence *fence)
 344{
 345        struct sync_timeline *parent = fence_parent(fence);
 346
 347        if (android_fence_signaled(fence))
 348                return false;
 349
 350        list_add_tail(&fence->active_list, &parent->active_list_head);
 351        return true;
 352}
 353
 354static void android_fence_value_str(struct fence *fence,
 355                                    char *str, int size)
 356{
 357        struct sync_timeline *parent = fence_parent(fence);
 358
 359        if (!parent->ops->fence_value_str) {
 360                if (size)
 361                        *str = 0;
 362                return;
 363        }
 364        parent->ops->fence_value_str(fence, str, size);
 365}
 366
 367static void android_fence_timeline_value_str(struct fence *fence,
 368                                             char *str, int size)
 369{
 370        struct sync_timeline *parent = fence_parent(fence);
 371
 372        if (!parent->ops->timeline_value_str) {
 373                if (size)
 374                        *str = 0;
 375                return;
 376        }
 377        parent->ops->timeline_value_str(parent, str, size);
 378}
 379
 380static const struct fence_ops android_fence_ops = {
 381        .get_driver_name = android_fence_get_driver_name,
 382        .get_timeline_name = android_fence_get_timeline_name,
 383        .enable_signaling = android_fence_enable_signaling,
 384        .signaled = android_fence_signaled,
 385        .wait = fence_default_wait,
 386        .release = android_fence_release,
 387        .fence_value_str = android_fence_value_str,
 388        .timeline_value_str = android_fence_timeline_value_str,
 389};
 390
 391static void sync_file_free(struct kref *kref)
 392{
 393        struct sync_file *sync_file = container_of(kref, struct sync_file,
 394                                                     kref);
 395        int i;
 396
 397        for (i = 0; i < sync_file->num_fences; ++i) {
 398                fence_remove_callback(sync_file->cbs[i].fence,
 399                                      &sync_file->cbs[i].cb);
 400                fence_put(sync_file->cbs[i].fence);
 401        }
 402
 403        kfree(sync_file);
 404}
 405
 406static int sync_file_release(struct inode *inode, struct file *file)
 407{
 408        struct sync_file *sync_file = file->private_data;
 409
 410        sync_file_debug_remove(sync_file);
 411
 412        kref_put(&sync_file->kref, sync_file_free);
 413        return 0;
 414}
 415
 416static unsigned int sync_file_poll(struct file *file, poll_table *wait)
 417{
 418        struct sync_file *sync_file = file->private_data;
 419        int status;
 420
 421        poll_wait(file, &sync_file->wq, wait);
 422
 423        status = atomic_read(&sync_file->status);
 424
 425        if (!status)
 426                return POLLIN;
 427        if (status < 0)
 428                return POLLERR;
 429        return 0;
 430}
 431
 432static long sync_file_ioctl_merge(struct sync_file *sync_file,
 433                                   unsigned long arg)
 434{
 435        int fd = get_unused_fd_flags(O_CLOEXEC);
 436        int err;
 437        struct sync_file *fence2, *fence3;
 438        struct sync_merge_data data;
 439
 440        if (fd < 0)
 441                return fd;
 442
 443        if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
 444                err = -EFAULT;
 445                goto err_put_fd;
 446        }
 447
 448        fence2 = sync_file_fdget(data.fd2);
 449        if (!fence2) {
 450                err = -ENOENT;
 451                goto err_put_fd;
 452        }
 453
 454        data.name[sizeof(data.name) - 1] = '\0';
 455        fence3 = sync_file_merge(data.name, sync_file, fence2);
 456        if (!fence3) {
 457                err = -ENOMEM;
 458                goto err_put_fence2;
 459        }
 460
 461        data.fence = fd;
 462        if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
 463                err = -EFAULT;
 464                goto err_put_fence3;
 465        }
 466
 467        sync_file_install(fence3, fd);
 468        sync_file_put(fence2);
 469        return 0;
 470
 471err_put_fence3:
 472        sync_file_put(fence3);
 473
 474err_put_fence2:
 475        sync_file_put(fence2);
 476
 477err_put_fd:
 478        put_unused_fd(fd);
 479        return err;
 480}
 481
 482static int sync_fill_fence_info(struct fence *fence, void *data, int size)
 483{
 484        struct sync_fence_info *info = data;
 485
 486        if (size < sizeof(*info))
 487                return -ENOMEM;
 488
 489        strlcpy(info->obj_name, fence->ops->get_timeline_name(fence),
 490                sizeof(info->obj_name));
 491        strlcpy(info->driver_name, fence->ops->get_driver_name(fence),
 492                sizeof(info->driver_name));
 493        if (fence_is_signaled(fence))
 494                info->status = fence->status >= 0 ? 1 : fence->status;
 495        else
 496                info->status = 0;
 497        info->timestamp_ns = ktime_to_ns(fence->timestamp);
 498
 499        return sizeof(*info);
 500}
 501
 502static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
 503                                        unsigned long arg)
 504{
 505        struct sync_file_info *info;
 506        __u32 size;
 507        __u32 len = 0;
 508        int ret, i;
 509
 510        if (copy_from_user(&size, (void __user *)arg, sizeof(size)))
 511                return -EFAULT;
 512
 513        if (size < sizeof(struct sync_file_info))
 514                return -EINVAL;
 515
 516        if (size > 4096)
 517                size = 4096;
 518
 519        info = kzalloc(size, GFP_KERNEL);
 520        if (!info)
 521                return -ENOMEM;
 522
 523        strlcpy(info->name, sync_file->name, sizeof(info->name));
 524        info->status = atomic_read(&sync_file->status);
 525        if (info->status >= 0)
 526                info->status = !info->status;
 527
 528        len = sizeof(struct sync_file_info);
 529
 530        for (i = 0; i < sync_file->num_fences; ++i) {
 531                struct fence *fence = sync_file->cbs[i].fence;
 532
 533                ret = sync_fill_fence_info(fence, (u8 *)info + len, size - len);
 534
 535                if (ret < 0)
 536                        goto out;
 537
 538                len += ret;
 539        }
 540
 541        info->len = len;
 542
 543        if (copy_to_user((void __user *)arg, info, len))
 544                ret = -EFAULT;
 545        else
 546                ret = 0;
 547
 548out:
 549        kfree(info);
 550
 551        return ret;
 552}
 553
 554static long sync_file_ioctl(struct file *file, unsigned int cmd,
 555                             unsigned long arg)
 556{
 557        struct sync_file *sync_file = file->private_data;
 558
 559        switch (cmd) {
 560        case SYNC_IOC_MERGE:
 561                return sync_file_ioctl_merge(sync_file, arg);
 562
 563        case SYNC_IOC_FENCE_INFO:
 564                return sync_file_ioctl_fence_info(sync_file, arg);
 565
 566        default:
 567                return -ENOTTY;
 568        }
 569}
 570
 571static const struct file_operations sync_file_fops = {
 572        .release = sync_file_release,
 573        .poll = sync_file_poll,
 574        .unlocked_ioctl = sync_file_ioctl,
 575        .compat_ioctl = sync_file_ioctl,
 576};
 577
 578