diff options
Diffstat (limited to 'drivers/gpu/pvr/services4/srvkm/env/linux/pvr_sw_fence.c')
-rw-r--r-- | drivers/gpu/pvr/services4/srvkm/env/linux/pvr_sw_fence.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/services4/srvkm/env/linux/pvr_sw_fence.c b/drivers/gpu/pvr/services4/srvkm/env/linux/pvr_sw_fence.c new file mode 100644 index 000000000000..7c3006d711f2 --- /dev/null +++ b/drivers/gpu/pvr/services4/srvkm/env/linux/pvr_sw_fence.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* -*- mode: c; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ | ||
2 | /* vi: set ts=8 sw=8 sts=8: */ | ||
3 | /*************************************************************************/ /*! | ||
4 | @File | ||
5 | @Codingstyle LinuxKernel | ||
6 | @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved | ||
7 | @License Strictly Confidential. | ||
8 | */ /**************************************************************************/ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/spinlock_types.h> | ||
12 | #include <linux/atomic.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/printk.h> | ||
15 | #include <linux/bug.h> | ||
16 | #include <linux/sync_file.h> | ||
17 | |||
18 | #include "img_types.h" | ||
19 | #include "services_headers.h" | ||
20 | #include "servicesext.h" | ||
21 | #include "pvr_sw_fence.h" | ||
22 | |||
23 | struct PVR_SW_FENCE_CONTEXT | ||
24 | { | ||
25 | struct kref sRef; | ||
26 | IMG_INT32 i32ContextId; | ||
27 | const char *psCtxName; | ||
28 | const char *psDriverName; | ||
29 | atomic_t sSeqno; | ||
30 | atomic_t sFenceCnt; | ||
31 | }; | ||
32 | |||
33 | struct PVR_SW_FENCE | ||
34 | { | ||
35 | struct dma_fence sBase; | ||
36 | struct PVR_SW_FENCE_CONTEXT *psSWFenceCtx; | ||
37 | spinlock_t sLock; | ||
38 | }; | ||
39 | |||
40 | #define to_pvr_sw_fence(fence) container_of(fence, struct PVR_SW_FENCE, sBase) | ||
41 | |||
42 | static inline unsigned | ||
43 | pvr_sw_fence_context_seqno_next(struct PVR_SW_FENCE_CONTEXT *psSWFenceCtx) | ||
44 | { | ||
45 | return atomic_inc_return(&psSWFenceCtx->sSeqno) - 1; | ||
46 | } | ||
47 | |||
48 | static const char * pvr_sw_fence_get_driver_name(struct dma_fence *psFence) | ||
49 | { | ||
50 | struct PVR_SW_FENCE *psPVRSwFence = to_pvr_sw_fence(psFence); | ||
51 | |||
52 | return psPVRSwFence->psSWFenceCtx->psDriverName; | ||
53 | } | ||
54 | |||
55 | static const char * pvr_sw_fence_get_timeline_name(struct dma_fence *psFence) | ||
56 | { | ||
57 | struct PVR_SW_FENCE *psPVRSwFence = to_pvr_sw_fence(psFence); | ||
58 | |||
59 | return psPVRSwFence->psSWFenceCtx->psCtxName; | ||
60 | } | ||
61 | |||
62 | static bool pvr_sw_fence_enable_signaling(struct dma_fence *psFence) | ||
63 | { | ||
64 | return true; | ||
65 | } | ||
66 | |||
67 | static void pvr_sw_fence_context_destroy_kref(struct kref *kref) | ||
68 | { | ||
69 | struct PVR_SW_FENCE_CONTEXT *psPVRSwFence = container_of(kref, struct PVR_SW_FENCE_CONTEXT, sRef); | ||
70 | unsigned fence_count; | ||
71 | |||
72 | fence_count = atomic_read(&psPVRSwFence->sFenceCnt); | ||
73 | if (WARN_ON(fence_count)) | ||
74 | pr_debug("%s context has %u fence(s) remaining\n", psPVRSwFence->psCtxName, fence_count); | ||
75 | |||
76 | kfree(psPVRSwFence); | ||
77 | } | ||
78 | |||
79 | static void pvr_sw_fence_release(struct dma_fence *psFence) | ||
80 | { | ||
81 | struct PVR_SW_FENCE *psPVRSwFence = to_pvr_sw_fence(psFence); | ||
82 | |||
83 | atomic_dec(&psPVRSwFence->psSWFenceCtx->sFenceCnt); | ||
84 | kref_put(&psPVRSwFence->psSWFenceCtx->sRef, | ||
85 | pvr_sw_fence_context_destroy_kref); | ||
86 | kfree(psPVRSwFence); | ||
87 | } | ||
88 | |||
89 | static struct dma_fence_ops pvr_sw_fence_ops = { | ||
90 | .get_driver_name = pvr_sw_fence_get_driver_name, | ||
91 | .get_timeline_name = pvr_sw_fence_get_timeline_name, | ||
92 | .enable_signaling = pvr_sw_fence_enable_signaling, | ||
93 | .wait = dma_fence_default_wait, | ||
94 | .release = pvr_sw_fence_release, | ||
95 | }; | ||
96 | |||
97 | struct PVR_SW_FENCE_CONTEXT * | ||
98 | pvr_sw_fence_context_create(const char *context_name, const char *driver_name) | ||
99 | { | ||
100 | struct PVR_SW_FENCE_CONTEXT *psSWFenceCtx; | ||
101 | |||
102 | psSWFenceCtx = kmalloc(sizeof(*psSWFenceCtx), GFP_KERNEL); | ||
103 | if (!psSWFenceCtx) | ||
104 | return NULL; | ||
105 | |||
106 | psSWFenceCtx->i32ContextId = dma_fence_context_alloc(1); | ||
107 | psSWFenceCtx->psCtxName = context_name; | ||
108 | psSWFenceCtx->psDriverName = driver_name; | ||
109 | atomic_set(&psSWFenceCtx->sSeqno, 0); | ||
110 | atomic_set(&psSWFenceCtx->sFenceCnt, 0); | ||
111 | kref_init(&psSWFenceCtx->sRef); | ||
112 | |||
113 | return psSWFenceCtx; | ||
114 | } | ||
115 | |||
116 | void pvr_sw_fence_context_destroy(struct PVR_SW_FENCE_CONTEXT *psSWFenceCtx) | ||
117 | { | ||
118 | kref_put(&psSWFenceCtx->sRef, pvr_sw_fence_context_destroy_kref); | ||
119 | } | ||
120 | |||
121 | struct dma_fence * | ||
122 | pvr_sw_fence_create(struct PVR_SW_FENCE_CONTEXT *psSWFenceCtx) | ||
123 | { | ||
124 | struct PVR_SW_FENCE *psPVRSwFence; | ||
125 | unsigned int seqno; | ||
126 | |||
127 | psPVRSwFence = kmalloc(sizeof(*psPVRSwFence), GFP_KERNEL); | ||
128 | if (!psPVRSwFence) | ||
129 | return NULL; | ||
130 | |||
131 | spin_lock_init(&psPVRSwFence->sLock); | ||
132 | psPVRSwFence->psSWFenceCtx = psSWFenceCtx; | ||
133 | |||
134 | seqno = pvr_sw_fence_context_seqno_next(psSWFenceCtx); | ||
135 | dma_fence_init(&psPVRSwFence->sBase, &pvr_sw_fence_ops, &psPVRSwFence->sLock, psSWFenceCtx->i32ContextId, seqno); | ||
136 | |||
137 | atomic_inc(&psSWFenceCtx->sFenceCnt); | ||
138 | kref_get(&psSWFenceCtx->sRef); | ||
139 | |||
140 | return &psPVRSwFence->sBase; | ||
141 | } | ||