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 irq handler and workqueue (in recover path) */ 50 void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) 51 { 52 unsigned long flags; 53 54 spin_lock_irqsave(&fctx->spinlock, flags); 55 fctx->completed_fence = max(fence, fctx->completed_fence); 56 spin_unlock_irqrestore(&fctx->spinlock, flags); 57 } 58 59 struct msm_fence { 60 struct dma_fence base; 61 struct msm_fence_context *fctx; 62 }; 63 64 static inline struct msm_fence *to_msm_fence(struct dma_fence *fence) 65 { 66 return container_of(fence, struct msm_fence, base); 67 } 68 69 static const char *msm_fence_get_driver_name(struct dma_fence *fence) 70 { 71 return "msm"; 72 } 73 74 static const char *msm_fence_get_timeline_name(struct dma_fence *fence) 75 { 76 struct msm_fence *f = to_msm_fence(fence); 77 return f->fctx->name; 78 } 79 80 static bool msm_fence_signaled(struct dma_fence *fence) 81 { 82 struct msm_fence *f = to_msm_fence(fence); 83 return msm_fence_completed(f->fctx, f->base.seqno); 84 } 85 86 static const struct dma_fence_ops msm_fence_ops = { 87 .get_driver_name = msm_fence_get_driver_name, 88 .get_timeline_name = msm_fence_get_timeline_name, 89 .signaled = msm_fence_signaled, 90 }; 91 92 struct dma_fence * 93 msm_fence_alloc(struct msm_fence_context *fctx) 94 { 95 struct msm_fence *f; 96 97 f = kzalloc(sizeof(*f), GFP_KERNEL); 98 if (!f) 99 return ERR_PTR(-ENOMEM); 100 101 f->fctx = fctx; 102 103 dma_fence_init(&f->base, &msm_fence_ops, &fctx->spinlock, 104 fctx->context, ++fctx->last_fence); 105 106 return &f->base; 107 } 108