1 /*- 2 * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 27 #include "smartpqi_includes.h" 28 29 #ifndef LOCKFREE_STACK 30 31 /* 32 * Function used to release the tag from taglist. 33 */ 34 void 35 pqisrc_put_tag(pqi_taglist_t *taglist, uint32_t elem) 36 { 37 38 OS_ACQUIRE_SPINLOCK(&(taglist->lock)); 39 /* DBG_FUNC("IN\n");*/ 40 41 ASSERT(taglist->num_elem < taglist->max_elem); 42 43 if (taglist->num_elem < taglist->max_elem) { 44 taglist->elem_array[taglist->tail] = elem; 45 taglist->num_elem++; 46 taglist->tail = (taglist->tail + 1) % taglist->max_elem; 47 } 48 49 OS_RELEASE_SPINLOCK(&taglist->lock); 50 51 /* DBG_FUNC("OUT\n");*/ 52 } 53 54 /* 55 * Function used to get an unoccupied tag from the tag list. 56 */ 57 uint32_t 58 pqisrc_get_tag(pqi_taglist_t *taglist) 59 { 60 uint32_t elem = INVALID_ELEM; 61 62 /* DBG_FUNC("IN\n");*/ 63 64 OS_ACQUIRE_SPINLOCK(&taglist->lock); 65 66 ASSERT(taglist->num_elem > 0); 67 68 if (taglist->num_elem > 0) { 69 elem = taglist->elem_array[taglist->head]; 70 taglist->num_elem--; 71 taglist->head = (taglist->head + 1) % taglist->max_elem; 72 } 73 74 OS_RELEASE_SPINLOCK(&taglist->lock); 75 76 /* DBG_FUNC("OUT got %d\n", elem);*/ 77 return elem; 78 } 79 80 /* 81 * Initialize circular queue implementation of tag list. 82 */ 83 int 84 pqisrc_init_taglist(pqisrc_softstate_t *softs, pqi_taglist_t *taglist, 85 uint32_t max_elem) 86 { 87 int ret = PQI_STATUS_SUCCESS; 88 int i = 0; 89 90 DBG_FUNC("IN\n"); 91 92 taglist->max_elem = max_elem; 93 taglist->num_elem = 0; 94 taglist->head = 0; 95 taglist->tail = 0; 96 taglist->elem_array = os_mem_alloc(softs, 97 (max_elem * sizeof(uint32_t))); 98 if (!(taglist->elem_array)) { 99 DBG_FUNC("Unable to allocate memory for taglist\n"); 100 ret = PQI_STATUS_FAILURE; 101 goto err_out; 102 } 103 104 os_strlcpy(taglist->lockname, "tag_lock", LOCKNAME_SIZE); 105 ret = os_init_spinlock(softs, &taglist->lock, taglist->lockname); 106 if(ret){ 107 DBG_ERR("tag lock initialization failed\n"); 108 taglist->lockcreated=false; 109 goto err_lock; 110 } 111 taglist->lockcreated = true; 112 113 /* indices 1 to max_elem are considered as valid tags */ 114 for (i=1; i <= max_elem; i++) { 115 softs->rcb[i].tag = INVALID_ELEM; 116 pqisrc_put_tag(taglist, i); 117 } 118 119 DBG_FUNC("OUT\n"); 120 return ret; 121 122 err_lock: 123 os_mem_free(softs, (char *)taglist->elem_array, 124 (taglist->max_elem * sizeof(uint32_t))); 125 taglist->elem_array = NULL; 126 err_out: 127 DBG_FUNC("OUT failed\n"); 128 return ret; 129 } 130 131 /* 132 * Destroy circular queue implementation of tag list. 133 */ 134 void 135 pqisrc_destroy_taglist(pqisrc_softstate_t *softs, pqi_taglist_t *taglist) 136 { 137 DBG_FUNC("IN\n"); 138 os_mem_free(softs, (char *)taglist->elem_array, 139 (taglist->max_elem * sizeof(uint32_t))); 140 taglist->elem_array = NULL; 141 142 if(taglist->lockcreated==true){ 143 os_uninit_spinlock(&taglist->lock); 144 taglist->lockcreated = false; 145 } 146 147 DBG_FUNC("OUT\n"); 148 } 149 150 #else /* LOCKFREE_STACK */ 151 152 /* 153 * Initialize circular queue implementation of tag list. 154 */ 155 int 156 pqisrc_init_taglist(pqisrc_softstate_t *softs, lockless_stack_t *stack, 157 uint32_t max_elem) 158 { 159 int ret = PQI_STATUS_SUCCESS; 160 int index = 0; 161 162 DBG_FUNC("IN\n"); 163 164 /* indices 1 to max_elem are considered as valid tags */ 165 stack->max_elem = max_elem + 1; 166 stack->head.data = 0; 167 DBG_INFO("Stack head address :%p\n",&stack->head); 168 169 /*Allocate memory for stack*/ 170 stack->next_index_array = (uint32_t*)os_mem_alloc(softs, 171 (stack->max_elem * sizeof(uint32_t))); 172 if (!(stack->next_index_array)) { 173 DBG_ERR("Unable to allocate memory for stack\n"); 174 ret = PQI_STATUS_FAILURE; 175 goto err_out; 176 } 177 178 /* push all the entries to the stack */ 179 for (index = 1; index < stack->max_elem ; index++) { 180 softs->rcb[index].tag = INVALID_ELEM; 181 pqisrc_put_tag(stack, index); 182 } 183 184 DBG_FUNC("OUT\n"); 185 return ret; 186 err_out: 187 DBG_FUNC("Failed OUT\n"); 188 return ret; 189 } 190 191 /* 192 * Destroy circular queue implementation of tag list. 193 */ 194 void 195 pqisrc_destroy_taglist(pqisrc_softstate_t *softs, lockless_stack_t *stack) 196 { 197 DBG_FUNC("IN\n"); 198 199 /* de-allocate stack memory */ 200 if (stack->next_index_array) { 201 os_mem_free(softs,(char*)stack->next_index_array, 202 (stack->max_elem * sizeof(uint32_t))); 203 stack->next_index_array = NULL; 204 } 205 206 DBG_FUNC("OUT\n"); 207 } 208 209 /* 210 * Function used to release the tag from taglist. 211 */ 212 void 213 pqisrc_put_tag(lockless_stack_t *stack, uint32_t index) 214 { 215 union head_list cur_head, new_head; 216 217 DBG_FUNC("IN\n"); 218 DBG_INFO("push tag :%u\n",index); 219 220 if (index >= stack->max_elem) { 221 ASSERT(false); 222 DBG_INFO("Pushed Invalid index\n"); /* stack full */ 223 return; 224 } 225 226 if (stack->next_index_array[index] != 0) { 227 ASSERT(false); 228 DBG_INFO("Index already present as tag in the stack\n"); 229 return; 230 } 231 232 do { 233 cur_head = stack->head; 234 /* increment seq_no */ 235 new_head.top.seq_no = cur_head.top.seq_no + 1; 236 /* update the index at the top of the stack with the new index */ 237 new_head.top.index = index; 238 /* Create a link to the previous index */ 239 stack->next_index_array[index] = cur_head.top.index; 240 }while(!os_atomic64_cas(&stack->head.data,cur_head.data,new_head.data)); 241 stack->num_elem++; 242 DBG_FUNC("OUT\n"); 243 return; 244 } 245 246 /* 247 * Function used to get an unoccupied tag from the tag list. 248 */ 249 uint32_t 250 pqisrc_get_tag(lockless_stack_t *stack) 251 { 252 union head_list cur_head, new_head; 253 254 DBG_FUNC("IN\n"); 255 do { 256 cur_head = stack->head; 257 if (cur_head.top.index == 0) /* stack empty */ 258 return INVALID_ELEM; 259 /* increment seq_no field */ 260 new_head.top.seq_no = cur_head.top.seq_no + 1; 261 /* update the index at the top of the stack with the next index */ 262 new_head.top.index = stack->next_index_array[cur_head.top.index]; 263 }while(!os_atomic64_cas(&stack->head.data,cur_head.data,new_head.data)); 264 stack->next_index_array[cur_head.top.index] = 0; 265 stack->num_elem--; 266 267 DBG_INFO("pop tag: %u\n",cur_head.top.index); 268 DBG_FUNC("OUT\n"); 269 return cur_head.top.index; /*tag*/ 270 } 271 #endif /* LOCKFREE_STACK */ 272