1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2013-2016 Red Hat 4 * Author: Rob Clark <robdclark@gmail.com> 5 */ 6 7 #include <linux/dma-fence.h> 8 9 #include "msm_drv.h" 10 #include "msm_fence.h" 11 12 13 struct msm_fence_context * 14 msm_fence_context_alloc(struct drm_device *dev, volatile uint32_t *fenceptr, 15 const char *name) 16 { 17 struct msm_fence_context *fctx; 18 19 fctx = kzalloc(sizeof(*fctx), GFP_KERNEL); 20 if (!fctx) 21 return ERR_PTR(-ENOMEM); 22 23 fctx->dev = dev; 24 strncpy(fctx->name, name, sizeof(fctx->name)); 25 fctx->context = dma_fence_context_alloc(1); 26 fctx->fenceptr = fenceptr; 27 spin_lock_init(&fctx->spinlock); 28 29 return fctx; 30 } 31 32 void msm_fence_context_free(struct msm_fence_context *fctx) 33 { 34 kfree(fctx); 35 } 36 37 static inline bool fence_completed(struct msm_fence_context *fctx, uint32_t fence) 38 { 39 /* 40 * Note: Check completed_fence first, as fenceptr is in a write-combine 41 * mapping, so it will be more expensive to read. 42 */ 43 return (int32_t)(fctx->completed_fence - fence) >= 0 || 44 (int32_t)(*fctx->fenceptr - fence) >= 0; 45 } 46 47 /* called from workqueue */ 48 void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) 49 { 50 spin_lock(&fctx->spinlock); 51 fctx->completed_fence = max(fence, fctx->completed_fence); 52 spin_unlock(&fctx->spinlock); 53 } 54 55 struct msm_fence { 56 struct dma_fence base; 57 struct msm_fence_context *fctx; 58 }; 59 60 static inline struct msm_fence *to_msm_fence(struct dma_fence *fence) 61 { 62 return container_of(fence, struct msm_fence, base); 63 } 64 65 static const char *msm_fence_get_driver_name(struct dma_fence *fence) 66 { 67 return "msm"; 68 } 69 70 static const char *msm_fence_get_timeline_name(struct dma_fence *fence) 71 { 72 struct msm_fence *f = to_msm_fence(fence); 73 return f->fctx->name; 74 } 75 76 static bool msm_fence_signaled(struct dma_fence *fence) 77 { 78 struct msm_fence *f = to_msm_fence(fence); 79 return fence_completed(f->fctx, f->base.seqno); 80 } 81 82 static const struct dma_fence_ops msm_fence_ops = { 83 .get_driver_name = msm_fence_get_driver_name, 84 .get_timeline_name = msm_fence_get_timeline_name, 85 .signaled = msm_fence_signaled, 86 }; 87 88 struct dma_fence * 89 msm_fence_alloc(struct msm_fence_context *fctx) 90 { 91 struct msm_fence *f; 92 93 f = kzalloc(sizeof(*f), GFP_KERNEL); 94 if (!f) 95 return ERR_PTR(-ENOMEM); 96 97 f->fctx = fctx; 98 99 dma_fence_init(&f->base, &msm_fence_ops, &fctx->spinlock, 100 fctx->context, ++fctx->last_fence); 101 102 return &f->base; 103 } 104