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
pqisrc_put_tag(pqi_taglist_t * taglist,uint32_t elem)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
pqisrc_get_tag(pqi_taglist_t * taglist)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
pqisrc_init_taglist(pqisrc_softstate_t * softs,pqi_taglist_t * taglist,uint32_t max_elem)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
pqisrc_destroy_taglist(pqisrc_softstate_t * softs,pqi_taglist_t * taglist)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
pqisrc_init_taglist(pqisrc_softstate_t * softs,lockless_stack_t * stack,uint32_t max_elem)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
pqisrc_destroy_taglist(pqisrc_softstate_t * softs,lockless_stack_t * stack)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
pqisrc_put_tag(lockless_stack_t * stack,uint32_t index)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
pqisrc_get_tag(lockless_stack_t * stack)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