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