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 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 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 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 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 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 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 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 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