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