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 strscpy(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 /* 32 * Start out close to the 32b fence rollover point, so we can 33 * catch bugs with fence comparisons. 34 */ 35 fctx->last_fence = 0xffffff00; 36 fctx->completed_fence = fctx->last_fence; 37 *fctx->fenceptr = fctx->last_fence; 38 39 return fctx; 40 } 41 42 void msm_fence_context_free(struct msm_fence_context *fctx) 43 { 44 kfree(fctx); 45 } 46 47 bool msm_fence_completed(struct msm_fence_context *fctx, uint32_t fence) 48 { 49 /* 50 * Note: Check completed_fence first, as fenceptr is in a write-combine 51 * mapping, so it will be more expensive to read. 52 */ 53 return (int32_t)(fctx->completed_fence - fence) >= 0 || 54 (int32_t)(*fctx->fenceptr - fence) >= 0; 55 } 56 57 /* called from irq handler and workqueue (in recover path) */ 58 void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) 59 { 60 unsigned long flags; 61 62 spin_lock_irqsave(&fctx->spinlock, flags); 63 if (fence_after(fence, fctx->completed_fence)) 64 fctx->completed_fence = fence; 65 spin_unlock_irqrestore(&fctx->spinlock, flags); 66 } 67 68 struct msm_fence { 69 struct dma_fence base; 70 struct msm_fence_context *fctx; 71 }; 72 73 static inline struct msm_fence *to_msm_fence(struct dma_fence *fence) 74 { 75 return container_of(fence, struct msm_fence, base); 76 } 77 78 static const char *msm_fence_get_driver_name(struct dma_fence *fence) 79 { 80 return "msm"; 81 } 82 83 static const char *msm_fence_get_timeline_name(struct dma_fence *fence) 84 { 85 struct msm_fence *f = to_msm_fence(fence); 86 return f->fctx->name; 87 } 88 89 static bool msm_fence_signaled(struct dma_fence *fence) 90 { 91 struct msm_fence *f = to_msm_fence(fence); 92 return msm_fence_completed(f->fctx, f->base.seqno); 93 } 94 95 static const struct dma_fence_ops msm_fence_ops = { 96 .get_driver_name = msm_fence_get_driver_name, 97 .get_timeline_name = msm_fence_get_timeline_name, 98 .signaled = msm_fence_signaled, 99 }; 100 101 struct dma_fence * 102 msm_fence_alloc(struct msm_fence_context *fctx) 103 { 104 struct msm_fence *f; 105 106 f = kzalloc(sizeof(*f), GFP_KERNEL); 107 if (!f) 108 return ERR_PTR(-ENOMEM); 109 110 f->fctx = fctx; 111 112 dma_fence_init(&f->base, &msm_fence_ops, &fctx->spinlock, 113 fctx->context, ++fctx->last_fence); 114 115 return &f->base; 116 } 117