1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2011-2021 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 #include <linux/atomic.h>
23 #include <linux/list.h>
24 #include <linux/spinlock.h>
25 #include <mali_kbase_fence.h>
26 #include <mali_kbase.h>
27
28 /* Spin lock protecting all Mali fences as fence->lock. */
29 static DEFINE_SPINLOCK(kbase_fence_lock);
30
31 #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
32 struct fence *
kbase_fence_out_new(struct kbase_jd_atom * katom)33 kbase_fence_out_new(struct kbase_jd_atom *katom)
34 #else
35 struct dma_fence *
36 kbase_fence_out_new(struct kbase_jd_atom *katom)
37 #endif
38 {
39 #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
40 struct fence *fence;
41 #else
42 struct dma_fence *fence;
43 #endif
44
45 WARN_ON(katom->dma_fence.fence);
46
47 fence = kzalloc(sizeof(*fence), GFP_KERNEL);
48 if (!fence)
49 return NULL;
50
51 dma_fence_init(fence,
52 &kbase_fence_ops,
53 &kbase_fence_lock,
54 katom->dma_fence.context,
55 atomic_inc_return(&katom->dma_fence.seqno));
56
57 katom->dma_fence.fence = fence;
58
59 return fence;
60 }
61
62 bool
kbase_fence_free_callbacks(struct kbase_jd_atom * katom)63 kbase_fence_free_callbacks(struct kbase_jd_atom *katom)
64 {
65 struct kbase_fence_cb *cb, *tmp;
66 bool res = false;
67
68 lockdep_assert_held(&katom->kctx->jctx.lock);
69
70 /* Clean up and free callbacks. */
71 list_for_each_entry_safe(cb, tmp, &katom->dma_fence.callbacks, node) {
72 bool ret;
73
74 /* Cancel callbacks that hasn't been called yet. */
75 ret = dma_fence_remove_callback(cb->fence, &cb->fence_cb);
76 if (ret) {
77 int ret;
78
79 /* Fence had not signaled, clean up after
80 * canceling.
81 */
82 ret = atomic_dec_return(&katom->dma_fence.dep_count);
83
84 if (unlikely(ret == 0))
85 res = true;
86 }
87
88 /*
89 * Release the reference taken in
90 * kbase_fence_add_callback().
91 */
92 dma_fence_put(cb->fence);
93 list_del(&cb->node);
94 kfree(cb);
95 }
96
97 return res;
98 }
99
100 #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
101 int
kbase_fence_add_callback(struct kbase_jd_atom * katom,struct fence * fence,fence_func_t callback)102 kbase_fence_add_callback(struct kbase_jd_atom *katom,
103 struct fence *fence,
104 fence_func_t callback)
105 #else
106 int
107 kbase_fence_add_callback(struct kbase_jd_atom *katom,
108 struct dma_fence *fence,
109 dma_fence_func_t callback)
110 #endif
111 {
112 int err = 0;
113 struct kbase_fence_cb *kbase_fence_cb;
114
115 if (!fence)
116 return -EINVAL;
117
118 kbase_fence_cb = kmalloc(sizeof(*kbase_fence_cb), GFP_KERNEL);
119 if (!kbase_fence_cb)
120 return -ENOMEM;
121
122 kbase_fence_cb->fence = fence;
123 kbase_fence_cb->katom = katom;
124 INIT_LIST_HEAD(&kbase_fence_cb->node);
125 atomic_inc(&katom->dma_fence.dep_count);
126
127 err = dma_fence_add_callback(fence, &kbase_fence_cb->fence_cb,
128 callback);
129 if (err == -ENOENT) {
130 /* Fence signaled, get the completion result */
131 err = dma_fence_get_status(fence);
132
133 /* remap success completion to err code */
134 if (err == 1)
135 err = 0;
136
137 kfree(kbase_fence_cb);
138 atomic_dec(&katom->dma_fence.dep_count);
139 } else if (err) {
140 kfree(kbase_fence_cb);
141 atomic_dec(&katom->dma_fence.dep_count);
142 } else {
143 /*
144 * Get reference to fence that will be kept until callback gets
145 * cleaned up in kbase_fence_free_callbacks().
146 */
147 dma_fence_get(fence);
148 /* Add callback to katom's list of callbacks */
149 list_add(&kbase_fence_cb->node, &katom->dma_fence.callbacks);
150 }
151
152 return err;
153 }
154