1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2fde5de6cSRob Clark /* 3fde5de6cSRob Clark * Copyright (C) 2013-2016 Red Hat 4fde5de6cSRob Clark * Author: Rob Clark <robdclark@gmail.com> 5fde5de6cSRob Clark */ 6fde5de6cSRob Clark 7f54d1867SChris Wilson #include <linux/dma-fence.h> 8ca762a8aSRob Clark 9fde5de6cSRob Clark #include "msm_drv.h" 10fde5de6cSRob Clark #include "msm_fence.h" 11fde5de6cSRob Clark 12ca762a8aSRob Clark 13ca762a8aSRob Clark struct msm_fence_context * 14da3d378dSRob Clark msm_fence_context_alloc(struct drm_device *dev, volatile uint32_t *fenceptr, 15da3d378dSRob Clark const char *name) 16fde5de6cSRob Clark { 17ca762a8aSRob Clark struct msm_fence_context *fctx; 1895d1deb0SRob Clark static int index = 0; 19ca762a8aSRob Clark 20ca762a8aSRob Clark fctx = kzalloc(sizeof(*fctx), GFP_KERNEL); 21ca762a8aSRob Clark if (!fctx) 22ca762a8aSRob Clark return ERR_PTR(-ENOMEM); 23ca762a8aSRob Clark 24ca762a8aSRob Clark fctx->dev = dev; 25*d7fd8634SDmitry Baryshkov strscpy(fctx->name, name, sizeof(fctx->name)); 26f54d1867SChris Wilson fctx->context = dma_fence_context_alloc(1); 2795d1deb0SRob Clark fctx->index = index++; 28da3d378dSRob Clark fctx->fenceptr = fenceptr; 29b6295f9aSRob Clark spin_lock_init(&fctx->spinlock); 30ca762a8aSRob Clark 312311720aSRob Clark /* 322311720aSRob Clark * Start out close to the 32b fence rollover point, so we can 332311720aSRob Clark * catch bugs with fence comparisons. 342311720aSRob Clark */ 352311720aSRob Clark fctx->last_fence = 0xffffff00; 362311720aSRob Clark fctx->completed_fence = fctx->last_fence; 372311720aSRob Clark *fctx->fenceptr = fctx->last_fence; 382311720aSRob Clark 39ca762a8aSRob Clark return fctx; 40fde5de6cSRob Clark } 41fde5de6cSRob Clark 42ca762a8aSRob Clark void msm_fence_context_free(struct msm_fence_context *fctx) 43ca762a8aSRob Clark { 44ca762a8aSRob Clark kfree(fctx); 45ca762a8aSRob Clark } 46ca762a8aSRob Clark 4795d1deb0SRob Clark bool msm_fence_completed(struct msm_fence_context *fctx, uint32_t fence) 48ca762a8aSRob Clark { 49da3d378dSRob Clark /* 50da3d378dSRob Clark * Note: Check completed_fence first, as fenceptr is in a write-combine 51da3d378dSRob Clark * mapping, so it will be more expensive to read. 52da3d378dSRob Clark */ 53da3d378dSRob Clark return (int32_t)(fctx->completed_fence - fence) >= 0 || 54da3d378dSRob Clark (int32_t)(*fctx->fenceptr - fence) >= 0; 55ca762a8aSRob Clark } 56ca762a8aSRob Clark 573c7a5221SRob Clark /* called from irq handler and workqueue (in recover path) */ 58ca762a8aSRob Clark void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) 59fde5de6cSRob Clark { 603c7a5221SRob Clark unsigned long flags; 613c7a5221SRob Clark 623c7a5221SRob Clark spin_lock_irqsave(&fctx->spinlock, flags); 632311720aSRob Clark if (fence_after(fence, fctx->completed_fence)) 642311720aSRob Clark fctx->completed_fence = fence; 653c7a5221SRob Clark spin_unlock_irqrestore(&fctx->spinlock, flags); 66fde5de6cSRob Clark } 67b6295f9aSRob Clark 68b6295f9aSRob Clark struct msm_fence { 69f54d1867SChris Wilson struct dma_fence base; 703c30cc41SEric Anholt struct msm_fence_context *fctx; 71b6295f9aSRob Clark }; 72b6295f9aSRob Clark 73f54d1867SChris Wilson static inline struct msm_fence *to_msm_fence(struct dma_fence *fence) 74b6295f9aSRob Clark { 75b6295f9aSRob Clark return container_of(fence, struct msm_fence, base); 76b6295f9aSRob Clark } 77b6295f9aSRob Clark 78f54d1867SChris Wilson static const char *msm_fence_get_driver_name(struct dma_fence *fence) 79b6295f9aSRob Clark { 80b6295f9aSRob Clark return "msm"; 81b6295f9aSRob Clark } 82b6295f9aSRob Clark 83f54d1867SChris Wilson static const char *msm_fence_get_timeline_name(struct dma_fence *fence) 84b6295f9aSRob Clark { 85b6295f9aSRob Clark struct msm_fence *f = to_msm_fence(fence); 86b6295f9aSRob Clark return f->fctx->name; 87b6295f9aSRob Clark } 88b6295f9aSRob Clark 89f54d1867SChris Wilson static bool msm_fence_signaled(struct dma_fence *fence) 90b6295f9aSRob Clark { 91b6295f9aSRob Clark struct msm_fence *f = to_msm_fence(fence); 9295d1deb0SRob Clark return msm_fence_completed(f->fctx, f->base.seqno); 93b6295f9aSRob Clark } 94b6295f9aSRob Clark 95f54d1867SChris Wilson static const struct dma_fence_ops msm_fence_ops = { 96b6295f9aSRob Clark .get_driver_name = msm_fence_get_driver_name, 97b6295f9aSRob Clark .get_timeline_name = msm_fence_get_timeline_name, 98b6295f9aSRob Clark .signaled = msm_fence_signaled, 99b6295f9aSRob Clark }; 100b6295f9aSRob Clark 101f54d1867SChris Wilson struct dma_fence * 102b6295f9aSRob Clark msm_fence_alloc(struct msm_fence_context *fctx) 103b6295f9aSRob Clark { 104b6295f9aSRob Clark struct msm_fence *f; 105b6295f9aSRob Clark 106b6295f9aSRob Clark f = kzalloc(sizeof(*f), GFP_KERNEL); 107b6295f9aSRob Clark if (!f) 108b6295f9aSRob Clark return ERR_PTR(-ENOMEM); 109b6295f9aSRob Clark 110b6295f9aSRob Clark f->fctx = fctx; 111b6295f9aSRob Clark 112f54d1867SChris Wilson dma_fence_init(&f->base, &msm_fence_ops, &fctx->spinlock, 113b6295f9aSRob Clark fctx->context, ++fctx->last_fence); 114b6295f9aSRob Clark 115b6295f9aSRob Clark return &f->base; 116b6295f9aSRob Clark } 117