media: atomisp: get rid of most checks for ISP2401 version
[linux-2.6-microblaze.git] / drivers / staging / media / atomisp / pci / 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         u32 count;
29         hrt_vaddress data;
30         s32 id;
31 };
32
33 struct ia_css_refcount_list {
34         u32 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         u32 i;
44
45         if (ptr == 0)
46                 return NULL;
47         if (!myrefcount.items) {
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                 if ((&myrefcount.items[i])->data == 0) {
55                         if (firstfree) {
56                                 /* for new entry */
57                                 return &myrefcount.items[i];
58                         }
59                 }
60                 if ((&myrefcount.items[i])->data == ptr) {
61                         /* found entry */
62                         return &myrefcount.items[i];
63                 }
64         }
65         return NULL;
66 }
67
68 enum ia_css_err ia_css_refcount_init(uint32_t size)
69 {
70         enum ia_css_err err = IA_CSS_SUCCESS;
71
72         if (size == 0) {
73                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
74                                     "ia_css_refcount_init(): Size of 0 for Ref count init!\n");
75                 return IA_CSS_ERR_INVALID_ARGUMENTS;
76         }
77         if (myrefcount.items) {
78                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
79                                     "ia_css_refcount_init(): Ref count is already initialized\n");
80                 return IA_CSS_ERR_INTERNAL_ERROR;
81         }
82         myrefcount.items =
83             sh_css_malloc(sizeof(struct ia_css_refcount_entry) * size);
84         if (!myrefcount.items)
85                 err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY;
86         if (err == IA_CSS_SUCCESS) {
87                 memset(myrefcount.items, 0,
88                        sizeof(struct ia_css_refcount_entry) * size);
89                 myrefcount.size = size;
90         }
91         return err;
92 }
93
94 void ia_css_refcount_uninit(void)
95 {
96         struct ia_css_refcount_entry *entry;
97         u32 i;
98
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(s32 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);
139                 if (!entry)
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(s32 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         assert(false);
200
201         return false;
202 }
203
204 bool ia_css_refcount_is_single(hrt_vaddress ptr)
205 {
206         struct ia_css_refcount_entry *entry;
207
208         if (ptr == mmgr_NULL)
209                 return false;
210
211         entry = refcount_find_entry(ptr, false);
212
213         if (entry)
214                 return (entry->count == 1);
215
216         return true;
217 }
218
219 void ia_css_refcount_clear(s32 id, clear_func clear_func_ptr)
220 {
221         struct ia_css_refcount_entry *entry;
222         u32 i;
223         u32 count = 0;
224
225         assert(clear_func_ptr);
226         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_refcount_clear(%x)\n",
227                             id);
228
229         for (i = 0; i < myrefcount.size; i++) {
230                 /* driver verifier tool has issues with &arr[i]
231                    and prefers arr + i; as these are actually equivalent
232                    the line below uses + i
233                 */
234                 entry = myrefcount.items + i;
235                 if ((entry->data != mmgr_NULL) && (entry->id == id)) {
236                         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
237                                             "ia_css_refcount_clear: %x: 0x%x\n",
238                                             id, entry->data);
239                         if (clear_func_ptr) {
240                                 /* clear using provided function */
241                                 clear_func_ptr(entry->data);
242                         } else {
243                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
244                                                     "ia_css_refcount_clear: using hmm_free: no clear_func\n");
245                                 hmm_free(entry->data);
246                         }
247
248                         if (entry->count != 0) {
249                                 IA_CSS_WARNING("Ref count for entry %x is not zero!", entry->id);
250                         }
251
252                         assert(entry->count == 0);
253
254                         entry->data = mmgr_NULL;
255                         entry->count = 0;
256                         entry->id = 0;
257                         count++;
258                 }
259         }
260         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
261                             "ia_css_refcount_clear(%x): cleared %d\n", id,
262                             count);
263 }
264
265 bool ia_css_refcount_is_valid(hrt_vaddress ptr)
266 {
267         struct ia_css_refcount_entry *entry;
268
269         if (ptr == mmgr_NULL)
270                 return false;
271
272         entry = refcount_find_entry(ptr, false);
273
274         return entry;
275 }