xref: /openbmc/linux/drivers/gpu/drm/msm/msm_fence.c (revision d7fd8634)
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