linux/drivers/gpu/drm/msm/msm_fence.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2013-2016 Red Hat
   3 * Author: Rob Clark <robdclark@gmail.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License version 2 as published by
   7 * the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program.  If not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18#include <linux/fence.h>
  19
  20#include "msm_drv.h"
  21#include "msm_fence.h"
  22
  23
  24struct msm_fence_context *
  25msm_fence_context_alloc(struct drm_device *dev, const char *name)
  26{
  27        struct msm_fence_context *fctx;
  28
  29        fctx = kzalloc(sizeof(*fctx), GFP_KERNEL);
  30        if (!fctx)
  31                return ERR_PTR(-ENOMEM);
  32
  33        fctx->dev = dev;
  34        fctx->name = name;
  35        fctx->context = fence_context_alloc(1);
  36        init_waitqueue_head(&fctx->event);
  37        spin_lock_init(&fctx->spinlock);
  38
  39        return fctx;
  40}
  41
  42void msm_fence_context_free(struct msm_fence_context *fctx)
  43{
  44        kfree(fctx);
  45}
  46
  47static inline bool fence_completed(struct msm_fence_context *fctx, uint32_t fence)
  48{
  49        return (int32_t)(fctx->completed_fence - fence) >= 0;
  50}
  51
  52/* legacy path for WAIT_FENCE ioctl: */
  53int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence,
  54                ktime_t *timeout, bool interruptible)
  55{
  56        int ret;
  57
  58        if (fence > fctx->last_fence) {
  59                DRM_ERROR("%s: waiting on invalid fence: %u (of %u)\n",
  60                                fctx->name, fence, fctx->last_fence);
  61                return -EINVAL;
  62        }
  63
  64        if (!timeout) {
  65                /* no-wait: */
  66                ret = fence_completed(fctx, fence) ? 0 : -EBUSY;
  67        } else {
  68                unsigned long remaining_jiffies = timeout_to_jiffies(timeout);
  69
  70                if (interruptible)
  71                        ret = wait_event_interruptible_timeout(fctx->event,
  72                                fence_completed(fctx, fence),
  73                                remaining_jiffies);
  74                else
  75                        ret = wait_event_timeout(fctx->event,
  76                                fence_completed(fctx, fence),
  77                                remaining_jiffies);
  78
  79                if (ret == 0) {
  80                        DBG("timeout waiting for fence: %u (completed: %u)",
  81                                        fence, fctx->completed_fence);
  82                        ret = -ETIMEDOUT;
  83                } else if (ret != -ERESTARTSYS) {
  84                        ret = 0;
  85                }
  86        }
  87
  88        return ret;
  89}
  90
  91/* called from workqueue */
  92void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence)
  93{
  94        spin_lock(&fctx->spinlock);
  95        fctx->completed_fence = max(fence, fctx->completed_fence);
  96        spin_unlock(&fctx->spinlock);
  97
  98        wake_up_all(&fctx->event);
  99}
 100
 101struct msm_fence {
 102        struct msm_fence_context *fctx;
 103        struct fence base;
 104};
 105
 106static inline struct msm_fence *to_msm_fence(struct fence *fence)
 107{
 108        return container_of(fence, struct msm_fence, base);
 109}
 110
 111static const char *msm_fence_get_driver_name(struct fence *fence)
 112{
 113        return "msm";
 114}
 115
 116static const char *msm_fence_get_timeline_name(struct fence *fence)
 117{
 118        struct msm_fence *f = to_msm_fence(fence);
 119        return f->fctx->name;
 120}
 121
 122static bool msm_fence_enable_signaling(struct fence *fence)
 123{
 124        return true;
 125}
 126
 127static bool msm_fence_signaled(struct fence *fence)
 128{
 129        struct msm_fence *f = to_msm_fence(fence);
 130        return fence_completed(f->fctx, f->base.seqno);
 131}
 132
 133static void msm_fence_release(struct fence *fence)
 134{
 135        struct msm_fence *f = to_msm_fence(fence);
 136        kfree_rcu(f, base.rcu);
 137}
 138
 139static const struct fence_ops msm_fence_ops = {
 140        .get_driver_name = msm_fence_get_driver_name,
 141        .get_timeline_name = msm_fence_get_timeline_name,
 142        .enable_signaling = msm_fence_enable_signaling,
 143        .signaled = msm_fence_signaled,
 144        .wait = fence_default_wait,
 145        .release = msm_fence_release,
 146};
 147
 148struct fence *
 149msm_fence_alloc(struct msm_fence_context *fctx)
 150{
 151        struct msm_fence *f;
 152
 153        f = kzalloc(sizeof(*f), GFP_KERNEL);
 154        if (!f)
 155                return ERR_PTR(-ENOMEM);
 156
 157        f->fctx = fctx;
 158
 159        fence_init(&f->base, &msm_fence_ops, &fctx->spinlock,
 160                        fctx->context, ++fctx->last_fence);
 161
 162        return &f->base;
 163}
 164