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 static int index = 0; 19 20 fctx = kzalloc(sizeof(*fctx), GFP_KERNEL); 21 if (!fctx) 22 return ERR_PTR(-ENOMEM); 23 24 fctx->dev = dev; 25 strncpy(fctx->name, name, sizeof(fctx->name)); 26 fctx->context = dma_fence_context_alloc(1); 27 fctx->index = index++; 28 fctx->fenceptr = fenceptr; 29 spin_lock_init(&fctx->spinlock); 30 31 return fctx; 32 } 33 34 void msm_fence_context_free(struct msm_fence_context *fctx) 35 { 36 kfree(fctx); 37 } 38 39 bool msm_fence_completed(struct msm_fence_context *fctx, uint32_t fence) 40 { 41 /* 42 * Note: Check completed_fence first, as fenceptr is in a write-combine 43 * mapping, so it will be more expensive to read. 44 */ 45 return (int32_t)(fctx->completed_fence - fence) >= 0 || 46 (int32_t)(*fctx->fenceptr - fence) >= 0; 47 } 48 49 /* called from workqueue */ 50 void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) 51 { 52 spin_lock(&fctx->spinlock); 53 fctx->completed_fence = max(fence, fctx->completed_fence); 54 spin_unlock(&fctx->spinlock); 55 } 56 57 struct msm_fence { 58 struct dma_fence base; 59 struct msm_fence_context *fctx; 60 }; 61 62 static inline struct msm_fence *to_msm_fence(struct dma_fence *fence) 63 { 64 return container_of(fence, struct msm_fence, base); 65 } 66 67 static const char *msm_fence_get_driver_name(struct dma_fence *fence) 68 { 69 return "msm"; 70 } 71 72 static const char *msm_fence_get_timeline_name(struct dma_fence *fence) 73 { 74 struct msm_fence *f = to_msm_fence(fence); 75 return f->fctx->name; 76 } 77 78 static bool msm_fence_signaled(struct dma_fence *fence) 79 { 80 struct msm_fence *f = to_msm_fence(fence); 81 return msm_fence_completed(f->fctx, f->base.seqno); 82 } 83 84 static const struct dma_fence_ops msm_fence_ops = { 85 .get_driver_name = msm_fence_get_driver_name, 86 .get_timeline_name = msm_fence_get_timeline_name, 87 .signaled = msm_fence_signaled, 88 }; 89 90 struct dma_fence * 91 msm_fence_alloc(struct msm_fence_context *fctx) 92 { 93 struct msm_fence *f; 94 95 f = kzalloc(sizeof(*f), GFP_KERNEL); 96 if (!f) 97 return ERR_PTR(-ENOMEM); 98 99 f->fctx = fctx; 100 101 dma_fence_init(&f->base, &msm_fence_ops, &fctx->spinlock, 102 fctx->context, ++fctx->last_fence); 103 104 return &f->base; 105 } 106