1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Support for Intel Camera Imaging ISP subsystem.
4 * Copyright (c) 2015, Intel Corporation.
5 */
6
7 #include "hmm.h"
8
9 #include "ia_css_refcount.h"
10 #include "sh_css_defs.h"
11
12 #include "platform_support.h"
13
14 #include "assert_support.h"
15
16 #include "ia_css_debug.h"
17
18 /* TODO: enable for other memory aswell
19 now only for ia_css_ptr */
20 struct ia_css_refcount_entry {
21 u32 count;
22 ia_css_ptr data;
23 s32 id;
24 };
25
26 struct ia_css_refcount_list {
27 u32 size;
28 struct ia_css_refcount_entry *items;
29 };
30
31 static struct ia_css_refcount_list myrefcount;
32
refcount_find_entry(ia_css_ptr ptr,bool firstfree)33 static struct ia_css_refcount_entry *refcount_find_entry(ia_css_ptr ptr,
34 bool firstfree)
35 {
36 u32 i;
37
38 if (ptr == 0)
39 return NULL;
40 if (!myrefcount.items) {
41 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
42 "%s(): Ref count not initialized!\n", __func__);
43 return NULL;
44 }
45
46 for (i = 0; i < myrefcount.size; i++) {
47 if ((&myrefcount.items[i])->data == 0) {
48 if (firstfree) {
49 /* for new entry */
50 return &myrefcount.items[i];
51 }
52 }
53 if ((&myrefcount.items[i])->data == ptr) {
54 /* found entry */
55 return &myrefcount.items[i];
56 }
57 }
58 return NULL;
59 }
60
ia_css_refcount_init(uint32_t size)61 int ia_css_refcount_init(uint32_t size)
62 {
63 int err = 0;
64
65 if (size == 0) {
66 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
67 "%s(): Size of 0 for Ref count init!\n", __func__);
68 return -EINVAL;
69 }
70 if (myrefcount.items) {
71 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
72 "%s(): Ref count is already initialized\n", __func__);
73 return -EINVAL;
74 }
75 myrefcount.items =
76 kvmalloc(sizeof(struct ia_css_refcount_entry) * size, GFP_KERNEL);
77 if (!myrefcount.items)
78 err = -ENOMEM;
79 if (!err) {
80 memset(myrefcount.items, 0,
81 sizeof(struct ia_css_refcount_entry) * size);
82 myrefcount.size = size;
83 }
84 return err;
85 }
86
ia_css_refcount_uninit(void)87 void ia_css_refcount_uninit(void)
88 {
89 struct ia_css_refcount_entry *entry;
90 u32 i;
91
92 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
93 "%s() entry\n", __func__);
94 for (i = 0; i < myrefcount.size; i++) {
95 /* driver verifier tool has issues with &arr[i]
96 and prefers arr + i; as these are actually equivalent
97 the line below uses + i
98 */
99 entry = myrefcount.items + i;
100 if (entry->data != mmgr_NULL) {
101 /* ia_css_debug_dtrace(IA_CSS_DBG_TRACE,
102 "ia_css_refcount_uninit: freeing (%x)\n",
103 entry->data);*/
104 hmm_free(entry->data);
105 entry->data = mmgr_NULL;
106 entry->count = 0;
107 entry->id = 0;
108 }
109 }
110 kvfree(myrefcount.items);
111 myrefcount.items = NULL;
112 myrefcount.size = 0;
113 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
114 "%s() leave\n", __func__);
115 }
116
ia_css_refcount_increment(s32 id,ia_css_ptr ptr)117 ia_css_ptr ia_css_refcount_increment(s32 id, ia_css_ptr ptr)
118 {
119 struct ia_css_refcount_entry *entry;
120
121 if (ptr == mmgr_NULL)
122 return ptr;
123
124 entry = refcount_find_entry(ptr, false);
125
126 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
127 "%s(%x) 0x%x\n", __func__, id, ptr);
128
129 if (!entry) {
130 entry = refcount_find_entry(ptr, true);
131 assert(entry);
132 if (!entry)
133 return mmgr_NULL;
134 entry->id = id;
135 }
136
137 if (entry->id != id) {
138 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
139 "%s(): Ref count IDS do not match!\n", __func__);
140 return mmgr_NULL;
141 }
142
143 if (entry->data == ptr)
144 entry->count += 1;
145 else if (entry->data == mmgr_NULL) {
146 entry->data = ptr;
147 entry->count = 1;
148 } else
149 return mmgr_NULL;
150
151 return ptr;
152 }
153
ia_css_refcount_decrement(s32 id,ia_css_ptr ptr)154 bool ia_css_refcount_decrement(s32 id, ia_css_ptr ptr)
155 {
156 struct ia_css_refcount_entry *entry;
157
158 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
159 "%s(%x) 0x%x\n", __func__, id, ptr);
160
161 if (ptr == mmgr_NULL)
162 return false;
163
164 entry = refcount_find_entry(ptr, false);
165
166 if (entry) {
167 if (entry->id != id) {
168 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
169 "%s(): Ref count IDS do not match!\n", __func__);
170 return false;
171 }
172 if (entry->count > 0) {
173 entry->count -= 1;
174 if (entry->count == 0) {
175 /* ia_css_debug_dtrace(IA_CSS_DBEUG_TRACE,
176 "ia_css_refcount_decrement: freeing\n");*/
177 hmm_free(ptr);
178 entry->data = mmgr_NULL;
179 entry->id = 0;
180 }
181 return true;
182 }
183 }
184
185 /* SHOULD NOT HAPPEN: ptr not managed by refcount, or not
186 valid anymore */
187 if (entry)
188 IA_CSS_ERROR("id %x, ptr 0x%x entry %p entry->id %x entry->count %d\n",
189 id, ptr, entry, entry->id, entry->count);
190 else
191 IA_CSS_ERROR("entry NULL\n");
192 assert(false);
193
194 return false;
195 }
196
ia_css_refcount_is_single(ia_css_ptr ptr)197 bool ia_css_refcount_is_single(ia_css_ptr ptr)
198 {
199 struct ia_css_refcount_entry *entry;
200
201 if (ptr == mmgr_NULL)
202 return false;
203
204 entry = refcount_find_entry(ptr, false);
205
206 if (entry)
207 return (entry->count == 1);
208
209 return true;
210 }
211
ia_css_refcount_clear(s32 id,clear_func clear_func_ptr)212 void ia_css_refcount_clear(s32 id, clear_func clear_func_ptr)
213 {
214 struct ia_css_refcount_entry *entry;
215 u32 i;
216 u32 count = 0;
217
218 assert(clear_func_ptr);
219 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s(%x)\n",
220 __func__, id);
221
222 for (i = 0; i < myrefcount.size; i++) {
223 /* driver verifier tool has issues with &arr[i]
224 and prefers arr + i; as these are actually equivalent
225 the line below uses + i
226 */
227 entry = myrefcount.items + i;
228 if ((entry->data != mmgr_NULL) && (entry->id == id)) {
229 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
230 "%s: %x: 0x%x\n", __func__,
231 id, entry->data);
232 if (clear_func_ptr) {
233 /* clear using provided function */
234 clear_func_ptr(entry->data);
235 } else {
236 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
237 "%s: using hmm_free: no clear_func\n", __func__);
238 hmm_free(entry->data);
239 }
240
241 if (entry->count != 0) {
242 IA_CSS_WARNING("Ref count for entry %x is not zero!", entry->id);
243 }
244
245 assert(entry->count == 0);
246
247 entry->data = mmgr_NULL;
248 entry->count = 0;
249 entry->id = 0;
250 count++;
251 }
252 }
253 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
254 "%s(%x): cleared %d\n", __func__, id,
255 count);
256 }
257
ia_css_refcount_is_valid(ia_css_ptr ptr)258 bool ia_css_refcount_is_valid(ia_css_ptr ptr)
259 {
260 struct ia_css_refcount_entry *entry;
261
262 if (ptr == mmgr_NULL)
263 return false;
264
265 entry = refcount_find_entry(ptr, false);
266
267 return entry;
268 }
269