1 /*- 2 * Copyright 2016-2021 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 /* $FreeBSD$ */ 27 28 #include "smartpqi_includes.h" 29 30 #ifndef LOCKFREE_STACK 31 32 /* 33 * Function used to release the tag from taglist. 34 */ 35 void 36 pqisrc_put_tag(pqi_taglist_t *taglist, uint32_t elem) 37 { 38 39 OS_ACQUIRE_SPINLOCK(&(taglist->lock)); 40 DBG_FUNC("IN\n"); 41 42 ASSERT(taglist->num_elem < taglist->max_elem); 43 44 if (taglist->num_elem < taglist->max_elem) { 45 taglist->elem_array[taglist->tail] = elem; 46 taglist->num_elem++; 47 taglist->tail = (taglist->tail + 1) % taglist->max_elem; 48 } 49 50 OS_RELEASE_SPINLOCK(&taglist->lock); 51 52 DBG_FUNC("OUT\n"); 53 } 54 55 /* 56 * Function used to get an unoccupied tag from the tag list. 57 */ 58 uint32_t 59 pqisrc_get_tag(pqi_taglist_t *taglist) 60 { 61 uint32_t elem = INVALID_ELEM; 62 63 /* DBG_FUNC("IN\n");*/ 64 65 OS_ACQUIRE_SPINLOCK(&taglist->lock); 66 67 ASSERT(taglist->num_elem > 0); 68 69 if (taglist->num_elem > 0) { 70 elem = taglist->elem_array[taglist->head]; 71 taglist->num_elem--; 72 taglist->head = (taglist->head + 1) % taglist->max_elem; 73 } 74 75 OS_RELEASE_SPINLOCK(&taglist->lock); 76 77 /* DBG_FUNC("OUT got %d\n", elem);*/ 78 return elem; 79 } 80 81 /* 82 * Initialize circular queue implementation of tag list. 83 */ 84 int 85 pqisrc_init_taglist(pqisrc_softstate_t *softs, pqi_taglist_t *taglist, 86 uint32_t max_elem) 87 { 88 int ret = PQI_STATUS_SUCCESS; 89 int i = 0; 90 91 DBG_FUNC("IN\n"); 92 93 taglist->max_elem = max_elem; 94 taglist->num_elem = 0; 95 taglist->head = 0; 96 taglist->tail = 0; 97 taglist->elem_array = os_mem_alloc(softs, 98 (max_elem * sizeof(uint32_t))); 99 if (!(taglist->elem_array)) { 100 DBG_FUNC("Unable to allocate memory for taglist\n"); 101 ret = PQI_STATUS_FAILURE; 102 goto err_out; 103 } 104 105 os_strlcpy(taglist->lockname, "tag_lock", LOCKNAME_SIZE); 106 ret = os_init_spinlock(softs, &taglist->lock, taglist->lockname); 107 if(ret){ 108 DBG_ERR("tag lock initialization failed\n"); 109 taglist->lockcreated=false; 110 goto err_lock; 111 } 112 taglist->lockcreated = true; 113 114 /* indices 1 to max_elem are considered as valid tags */ 115 for (i=1; i <= max_elem; i++) { 116 softs->rcb[i].tag = INVALID_ELEM; 117 pqisrc_put_tag(taglist, i); 118 } 119 120 DBG_FUNC("OUT\n"); 121 return ret; 122 123 err_lock: 124 os_mem_free(softs, (char *)taglist->elem_array, 125 (taglist->max_elem * sizeof(uint32_t))); 126 taglist->elem_array = NULL; 127 err_out: 128 DBG_FUNC("OUT failed\n"); 129 return ret; 130 } 131 132 /* 133 * Destroy circular queue implementation of tag list. 134 */ 135 void 136 pqisrc_destroy_taglist(pqisrc_softstate_t *softs, pqi_taglist_t *taglist) 137 { 138 DBG_FUNC("IN\n"); 139 os_mem_free(softs, (char *)taglist->elem_array, 140 (taglist->max_elem * sizeof(uint32_t))); 141 taglist->elem_array = NULL; 142 143 if(taglist->lockcreated==true){ 144 os_uninit_spinlock(&taglist->lock); 145 taglist->lockcreated = false; 146 } 147 148 DBG_FUNC("OUT\n"); 149 } 150 151 #else /* LOCKFREE_STACK */ 152 153 /* 154 * Initialize circular queue implementation of tag list. 155 */ 156 int 157 pqisrc_init_taglist(pqisrc_softstate_t *softs, lockless_stack_t *stack, 158 uint32_t max_elem) 159 { 160 int ret = PQI_STATUS_SUCCESS; 161 int index = 0; 162 163 DBG_FUNC("IN\n"); 164 165 /* indices 1 to max_elem are considered as valid tags */ 166 stack->max_elem = max_elem + 1; 167 stack->head.data = 0; 168 DBG_INFO("Stack head address :%p\n",&stack->head); 169 170 /*Allocate memory for stack*/ 171 stack->next_index_array = (uint32_t*)os_mem_alloc(softs, 172 (stack->max_elem * sizeof(uint32_t))); 173 if (!(stack->next_index_array)) { 174 DBG_ERR("Unable to allocate memory for stack\n"); 175 ret = PQI_STATUS_FAILURE; 176 goto err_out; 177 } 178 179 /* push all the entries to the stack */ 180 for (index = 1; index < stack->max_elem ; index++) { 181 softs->rcb[index].tag = INVALID_ELEM; 182 pqisrc_put_tag(stack, index); 183 } 184 185 DBG_FUNC("OUT\n"); 186 return ret; 187 err_out: 188 DBG_FUNC("Failed OUT\n"); 189 return ret; 190 } 191 192 /* 193 * Destroy circular queue implementation of tag list. 194 */ 195 void 196 pqisrc_destroy_taglist(pqisrc_softstate_t *softs, lockless_stack_t *stack) 197 { 198 DBG_FUNC("IN\n"); 199 200 /* de-allocate stack memory */ 201 if (stack->next_index_array) { 202 os_mem_free(softs,(char*)stack->next_index_array, 203 (stack->max_elem * sizeof(uint32_t))); 204 stack->next_index_array = NULL; 205 } 206 207 DBG_FUNC("OUT\n"); 208 } 209 210 /* 211 * Function used to release the tag from taglist. 212 */ 213 void 214 pqisrc_put_tag(lockless_stack_t *stack, uint32_t index) 215 { 216 union head_list cur_head, new_head; 217 218 DBG_FUNC("IN\n"); 219 DBG_INFO("push tag :%d\n",index); 220 221 if (index >= stack->max_elem) { 222 ASSERT(false); 223 DBG_INFO("Pushed Invalid index\n"); /* stack full */ 224 return; 225 } 226 227 if (stack->next_index_array[index] != 0) { 228 ASSERT(false); 229 DBG_INFO("Index already present as tag in the stack\n"); 230 return; 231 } 232 233 do { 234 cur_head = stack->head; 235 /* increment seq_no */ 236 new_head.top.seq_no = cur_head.top.seq_no + 1; 237 /* update the index at the top of the stack with the new index */ 238 new_head.top.index = index; 239 /* Create a link to the previous index */ 240 stack->next_index_array[index] = cur_head.top.index; 241 }while(!os_atomic64_cas(&stack->head.data,cur_head.data,new_head.data)); 242 stack->num_elem++; 243 DBG_FUNC("OUT\n"); 244 return; 245 } 246 247 /* 248 * Function used to get an unoccupied tag from the tag list. 249 */ 250 uint32_t 251 pqisrc_get_tag(lockless_stack_t *stack) 252 { 253 union head_list cur_head, new_head; 254 255 DBG_FUNC("IN\n"); 256 do { 257 cur_head = stack->head; 258 if (cur_head.top.index == 0) /* stack empty */ 259 return INVALID_ELEM; 260 /* increment seq_no field */ 261 new_head.top.seq_no = cur_head.top.seq_no + 1; 262 /* update the index at the top of the stack with the next index */ 263 new_head.top.index = stack->next_index_array[cur_head.top.index]; 264 }while(!os_atomic64_cas(&stack->head.data,cur_head.data,new_head.data)); 265 stack->next_index_array[cur_head.top.index] = 0; 266 stack->num_elem--; 267 268 DBG_INFO("pop tag: %d\n",cur_head.top.index); 269 DBG_FUNC("OUT\n"); 270 return cur_head.top.index; /*tag*/ 271 } 272 #endif /* LOCKFREE_STACK */ 273