Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2013-2016 Red Hat
0004  * Author: Rob Clark <robdclark@gmail.com>
0005  */
0006 
0007 #include <linux/dma-fence.h>
0008 
0009 #include "msm_drv.h"
0010 #include "msm_fence.h"
0011 
0012 
0013 struct msm_fence_context *
0014 msm_fence_context_alloc(struct drm_device *dev, volatile uint32_t *fenceptr,
0015         const char *name)
0016 {
0017     struct msm_fence_context *fctx;
0018     static int index = 0;
0019 
0020     fctx = kzalloc(sizeof(*fctx), GFP_KERNEL);
0021     if (!fctx)
0022         return ERR_PTR(-ENOMEM);
0023 
0024     fctx->dev = dev;
0025     strncpy(fctx->name, name, sizeof(fctx->name));
0026     fctx->context = dma_fence_context_alloc(1);
0027     fctx->index = index++;
0028     fctx->fenceptr = fenceptr;
0029     spin_lock_init(&fctx->spinlock);
0030 
0031     /*
0032      * Start out close to the 32b fence rollover point, so we can
0033      * catch bugs with fence comparisons.
0034      */
0035     fctx->last_fence = 0xffffff00;
0036     fctx->completed_fence = fctx->last_fence;
0037     *fctx->fenceptr = fctx->last_fence;
0038 
0039     return fctx;
0040 }
0041 
0042 void msm_fence_context_free(struct msm_fence_context *fctx)
0043 {
0044     kfree(fctx);
0045 }
0046 
0047 bool msm_fence_completed(struct msm_fence_context *fctx, uint32_t fence)
0048 {
0049     /*
0050      * Note: Check completed_fence first, as fenceptr is in a write-combine
0051      * mapping, so it will be more expensive to read.
0052      */
0053     return (int32_t)(fctx->completed_fence - fence) >= 0 ||
0054         (int32_t)(*fctx->fenceptr - fence) >= 0;
0055 }
0056 
0057 /* called from irq handler and workqueue (in recover path) */
0058 void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence)
0059 {
0060     unsigned long flags;
0061 
0062     spin_lock_irqsave(&fctx->spinlock, flags);
0063     if (fence_after(fence, fctx->completed_fence))
0064         fctx->completed_fence = fence;
0065     spin_unlock_irqrestore(&fctx->spinlock, flags);
0066 }
0067 
0068 struct msm_fence {
0069     struct dma_fence base;
0070     struct msm_fence_context *fctx;
0071 };
0072 
0073 static inline struct msm_fence *to_msm_fence(struct dma_fence *fence)
0074 {
0075     return container_of(fence, struct msm_fence, base);
0076 }
0077 
0078 static const char *msm_fence_get_driver_name(struct dma_fence *fence)
0079 {
0080     return "msm";
0081 }
0082 
0083 static const char *msm_fence_get_timeline_name(struct dma_fence *fence)
0084 {
0085     struct msm_fence *f = to_msm_fence(fence);
0086     return f->fctx->name;
0087 }
0088 
0089 static bool msm_fence_signaled(struct dma_fence *fence)
0090 {
0091     struct msm_fence *f = to_msm_fence(fence);
0092     return msm_fence_completed(f->fctx, f->base.seqno);
0093 }
0094 
0095 static const struct dma_fence_ops msm_fence_ops = {
0096     .get_driver_name = msm_fence_get_driver_name,
0097     .get_timeline_name = msm_fence_get_timeline_name,
0098     .signaled = msm_fence_signaled,
0099 };
0100 
0101 struct dma_fence *
0102 msm_fence_alloc(struct msm_fence_context *fctx)
0103 {
0104     struct msm_fence *f;
0105 
0106     f = kzalloc(sizeof(*f), GFP_KERNEL);
0107     if (!f)
0108         return ERR_PTR(-ENOMEM);
0109 
0110     f->fctx = fctx;
0111 
0112     dma_fence_init(&f->base, &msm_fence_ops, &fctx->spinlock,
0113                fctx->context, ++fctx->last_fence);
0114 
0115     return &f->base;
0116 }