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