linux/drivers/staging/mali/DX910-SW-99002-r5p1-01rel0/driver/src/devicedrv/mali/linux/mali_sync.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012-2015 ARM Limited. All rights reserved.
   3 * 
   4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
   5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
   6 * 
   7 * A copy of the licence is included with the program, and can also be obtained from Free Software
   8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   9 */
  10
  11#include "mali_sync.h"
  12
  13#include "mali_osk.h"
  14#include "mali_kernel_common.h"
  15#include "mali_timeline.h"
  16
  17#include <linux/file.h>
  18#include <linux/seq_file.h>
  19#include <linux/module.h>
  20
  21struct mali_sync_pt {
  22        struct sync_pt         sync_pt;
  23        struct mali_sync_flag *flag;
  24        struct sync_timeline *sync_tl;  /**< Sync timeline this pt is connected to. */
  25};
  26
  27/**
  28 * The sync flag is used to connect sync fences to the Mali Timeline system.  Sync fences can be
  29 * created from a sync flag, and when the flag is signaled, the sync fences will also be signaled.
  30 */
  31struct mali_sync_flag {
  32        struct sync_timeline *sync_tl;  /**< Sync timeline this flag is connected to. */
  33        u32                   point;    /**< Point on timeline. */
  34        int                   status;   /**< 0 if unsignaled, 1 if signaled without error or negative if signaled with error. */
  35        struct kref           refcount; /**< Reference count. */
  36};
  37
  38/**
  39 * Mali sync timeline is used to connect mali timeline to sync_timeline.
  40 * When fence timeout can print more detailed mali timeline system info.
  41 */
  42struct mali_sync_timeline_container {
  43        struct sync_timeline sync_timeline;
  44        struct mali_timeline *timeline;
  45};
  46
  47MALI_STATIC_INLINE struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt)
  48{
  49        return container_of(pt, struct mali_sync_pt, sync_pt);
  50}
  51
  52MALI_STATIC_INLINE struct mali_sync_timeline_container *to_mali_sync_tl_container(struct sync_timeline *sync_tl)
  53{
  54        return container_of(sync_tl, struct mali_sync_timeline_container, sync_timeline);
  55}
  56
  57static struct sync_pt *timeline_dup(struct sync_pt *pt)
  58{
  59        struct mali_sync_pt *mpt, *new_mpt;
  60        struct sync_pt *new_pt;
  61
  62        MALI_DEBUG_ASSERT_POINTER(pt);
  63        mpt = to_mali_sync_pt(pt);
  64
  65        new_pt = sync_pt_create(mpt->sync_tl, sizeof(struct mali_sync_pt));
  66        if (NULL == new_pt) return NULL;
  67
  68        new_mpt = to_mali_sync_pt(new_pt);
  69
  70        mali_sync_flag_get(mpt->flag);
  71        new_mpt->flag = mpt->flag;
  72        new_mpt->sync_tl = mpt->sync_tl;
  73
  74        return new_pt;
  75}
  76
  77static int timeline_has_signaled(struct sync_pt *pt)
  78{
  79        struct mali_sync_pt *mpt;
  80
  81        MALI_DEBUG_ASSERT_POINTER(pt);
  82        mpt = to_mali_sync_pt(pt);
  83
  84        MALI_DEBUG_ASSERT_POINTER(mpt->flag);
  85
  86        return mpt->flag->status;
  87}
  88
  89static int timeline_compare(struct sync_pt *pta, struct sync_pt *ptb)
  90{
  91        struct mali_sync_pt *mpta;
  92        struct mali_sync_pt *mptb;
  93        u32 a, b;
  94
  95        MALI_DEBUG_ASSERT_POINTER(pta);
  96        MALI_DEBUG_ASSERT_POINTER(ptb);
  97        mpta = to_mali_sync_pt(pta);
  98        mptb = to_mali_sync_pt(ptb);
  99
 100        MALI_DEBUG_ASSERT_POINTER(mpta->flag);
 101        MALI_DEBUG_ASSERT_POINTER(mptb->flag);
 102
 103        a = mpta->flag->point;
 104        b = mptb->flag->point;
 105
 106        if (a == b) return 0;
 107
 108        return ((b - a) < (a - b) ? -1 : 1);
 109}
 110
 111static void timeline_free_pt(struct sync_pt *pt)
 112{
 113        struct mali_sync_pt *mpt;
 114
 115        MALI_DEBUG_ASSERT_POINTER(pt);
 116        mpt = to_mali_sync_pt(pt);
 117
 118        mali_sync_flag_put(mpt->flag);
 119}
 120
 121static void timeline_release(struct sync_timeline *sync_timeline)
 122{
 123        module_put(THIS_MODULE);
 124}
 125
 126#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
 127static void timeline_print_pt(struct seq_file *s, struct sync_pt *sync_pt)
 128{
 129        struct mali_sync_pt *mpt;
 130
 131        MALI_DEBUG_ASSERT_POINTER(s);
 132        MALI_DEBUG_ASSERT_POINTER(sync_pt);
 133
 134        mpt = to_mali_sync_pt(sync_pt);
 135
 136        /* It is possible this sync point is just under construct,
 137         * make sure the flag is valid before accessing it
 138        */
 139        if (mpt->flag) {
 140                seq_printf(s, "%u", mpt->flag->point);
 141        } else {
 142                seq_printf(s, "uninitialized");
 143        }
 144}
 145
 146#else
 147static void timeline_pt_value_str(struct sync_pt *pt, char *str, int size)
 148{
 149        struct mali_sync_pt *mpt;
 150
 151        MALI_DEBUG_ASSERT_POINTER(str);
 152        MALI_DEBUG_ASSERT_POINTER(pt);
 153
 154        mpt = to_mali_sync_pt(pt);
 155
 156        /* It is possible this sync point is just under construct,
 157         * make sure the flag is valid before accessing it
 158        */
 159        if (mpt->flag) {
 160                _mali_osk_snprintf(str, size, "%u", mpt->flag->point);
 161        } else {
 162                _mali_osk_snprintf(str, size, "uninitialized");
 163        }
 164}
 165
 166static void timeline_value_str(struct sync_timeline *timeline, char *str, int size)
 167{
 168        struct mali_sync_timeline_container *mali_sync_tl;
 169
 170        MALI_DEBUG_ASSERT_POINTER(timeline);
 171        MALI_DEBUG_ASSERT_POINTER(str);
 172
 173        mali_sync_tl = to_mali_sync_tl_container(timeline);
 174
 175        MALI_DEBUG_ASSERT_POINTER(mali_sync_tl);
 176
 177        if (NULL != mali_sync_tl->timeline) {
 178                _mali_osk_snprintf(str, size, "oldest (%u)  next (%u)\n", mali_sync_tl->timeline->point_oldest,
 179                                   mali_sync_tl->timeline->point_next);
 180        }
 181}
 182#endif
 183
 184static struct sync_timeline_ops mali_timeline_ops = {
 185        .driver_name    = "Mali",
 186        .dup            = timeline_dup,
 187        .has_signaled   = timeline_has_signaled,
 188        .compare        = timeline_compare,
 189        .free_pt        = timeline_free_pt,
 190        .release_obj    = timeline_release,
 191#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
 192        .print_pt       = timeline_print_pt,
 193#else
 194        .pt_value_str = timeline_pt_value_str,
 195        .timeline_value_str = timeline_value_str,
 196#endif
 197};
 198
 199struct sync_timeline *mali_sync_timeline_create(struct mali_timeline *timeline, const char *name)
 200{
 201        struct sync_timeline *sync_tl;
 202        struct mali_sync_timeline_container *mali_sync_tl;
 203
 204        sync_tl = sync_timeline_create(&mali_timeline_ops, sizeof(struct mali_sync_timeline_container), name);
 205        if (NULL == sync_tl) return NULL;
 206
 207        mali_sync_tl = to_mali_sync_tl_container(sync_tl);
 208        mali_sync_tl->timeline = timeline;
 209
 210        /* Grab a reference on the module to ensure the callbacks are present
 211         * as long some timeline exists. The reference is released when the
 212         * timeline is freed.
 213         * Since this function is called from a ioctl on an open file we know
 214         * we already have a reference, so using __module_get is safe. */
 215        __module_get(THIS_MODULE);
 216
 217        return sync_tl;
 218}
 219
 220mali_bool mali_sync_timeline_is_ours(struct sync_timeline *sync_tl)
 221{
 222        MALI_DEBUG_ASSERT_POINTER(sync_tl);
 223        return (sync_tl->ops == &mali_timeline_ops) ? MALI_TRUE : MALI_FALSE;
 224}
 225
 226s32 mali_sync_fence_fd_alloc(struct sync_fence *sync_fence)
 227{
 228        s32 fd = -1;
 229
 230        fd = get_unused_fd();
 231        if (fd < 0) {
 232                sync_fence_put(sync_fence);
 233                return -1;
 234        }
 235        sync_fence_install(sync_fence, fd);
 236
 237        return fd;
 238}
 239
 240struct sync_fence *mali_sync_fence_merge(struct sync_fence *sync_fence1, struct sync_fence *sync_fence2)
 241{
 242        struct sync_fence *sync_fence;
 243
 244        MALI_DEBUG_ASSERT_POINTER(sync_fence1);
 245        MALI_DEBUG_ASSERT_POINTER(sync_fence1);
 246
 247        sync_fence = sync_fence_merge("mali_merge_fence", sync_fence1, sync_fence2);
 248        sync_fence_put(sync_fence1);
 249        sync_fence_put(sync_fence2);
 250
 251        return sync_fence;
 252}
 253
 254struct sync_fence *mali_sync_timeline_create_signaled_fence(struct sync_timeline *sync_tl)
 255{
 256        struct mali_sync_flag *flag;
 257        struct sync_fence *sync_fence;
 258
 259        MALI_DEBUG_ASSERT_POINTER(sync_tl);
 260
 261        flag = mali_sync_flag_create(sync_tl, 0);
 262        if (NULL == flag) return NULL;
 263
 264        sync_fence = mali_sync_flag_create_fence(flag);
 265
 266        mali_sync_flag_signal(flag, 0);
 267        mali_sync_flag_put(flag);
 268
 269        return sync_fence;
 270}
 271
 272struct mali_sync_flag *mali_sync_flag_create(struct sync_timeline *sync_tl, mali_timeline_point point)
 273{
 274        struct mali_sync_flag *flag;
 275
 276        if (NULL == sync_tl) return NULL;
 277
 278        flag = _mali_osk_calloc(1, sizeof(*flag));
 279        if (NULL == flag) return NULL;
 280
 281        flag->sync_tl = sync_tl;
 282        flag->point = point;
 283
 284        flag->status = 0;
 285        kref_init(&flag->refcount);
 286
 287        return flag;
 288}
 289
 290void mali_sync_flag_get(struct mali_sync_flag *flag)
 291{
 292        MALI_DEBUG_ASSERT_POINTER(flag);
 293        kref_get(&flag->refcount);
 294}
 295
 296/**
 297 * Free sync flag.
 298 *
 299 * @param ref kref object embedded in sync flag that should be freed.
 300 */
 301static void mali_sync_flag_free(struct kref *ref)
 302{
 303        struct mali_sync_flag *flag;
 304
 305        MALI_DEBUG_ASSERT_POINTER(ref);
 306        flag = container_of(ref, struct mali_sync_flag, refcount);
 307
 308        _mali_osk_free(flag);
 309}
 310
 311void mali_sync_flag_put(struct mali_sync_flag *flag)
 312{
 313        MALI_DEBUG_ASSERT_POINTER(flag);
 314        kref_put(&flag->refcount, mali_sync_flag_free);
 315}
 316
 317void mali_sync_flag_signal(struct mali_sync_flag *flag, int error)
 318{
 319        MALI_DEBUG_ASSERT_POINTER(flag);
 320
 321        MALI_DEBUG_ASSERT(0 == flag->status);
 322        flag->status = (0 > error) ? error : 1;
 323
 324        _mali_osk_write_mem_barrier();
 325
 326        sync_timeline_signal(flag->sync_tl);
 327}
 328
 329/**
 330 * Create a sync point attached to given sync flag.
 331 *
 332 * @note Sync points must be triggered in *exactly* the same order as they are created.
 333 *
 334 * @param flag Sync flag.
 335 * @return New sync point if successful, NULL if not.
 336 */
 337static struct sync_pt *mali_sync_flag_create_pt(struct mali_sync_flag *flag)
 338{
 339        struct sync_pt *pt;
 340        struct mali_sync_pt *mpt;
 341
 342        MALI_DEBUG_ASSERT_POINTER(flag);
 343        MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
 344
 345        pt = sync_pt_create(flag->sync_tl, sizeof(struct mali_sync_pt));
 346        if (NULL == pt) return NULL;
 347
 348        mali_sync_flag_get(flag);
 349
 350        mpt = to_mali_sync_pt(pt);
 351        mpt->flag = flag;
 352        mpt->sync_tl = flag->sync_tl;
 353
 354        return pt;
 355}
 356
 357struct sync_fence *mali_sync_flag_create_fence(struct mali_sync_flag *flag)
 358{
 359        struct sync_pt    *sync_pt;
 360        struct sync_fence *sync_fence;
 361
 362        MALI_DEBUG_ASSERT_POINTER(flag);
 363        MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
 364
 365        sync_pt = mali_sync_flag_create_pt(flag);
 366        if (NULL == sync_pt) return NULL;
 367
 368        sync_fence = sync_fence_create("mali_flag_fence", sync_pt);
 369        if (NULL == sync_fence) {
 370                sync_pt_free(sync_pt);
 371                return NULL;
 372        }
 373
 374        return sync_fence;
 375}
 376