1 /*
2 * Copyright (c) 2014-2018, 2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: qdf_list.c
22 *
23 * QCA driver framework list manipulation APIs. QDF linked list
24 * APIs are NOT thread safe so make sure to use appropriate locking mechanisms
25 * to assure operations on the list are thread safe.
26 */
27
28 /* Include files */
29 #include <qdf_list.h>
30 #include <qdf_module.h>
31
32 /* Function declarations and documentation */
33
qdf_list_insert_before(qdf_list_t * list,qdf_list_node_t * new_node,qdf_list_node_t * node)34 QDF_STATUS qdf_list_insert_before(qdf_list_t *list,
35 qdf_list_node_t *new_node, qdf_list_node_t *node)
36 {
37 list_add_tail(new_node, node);
38 list->count++;
39
40 return QDF_STATUS_SUCCESS;
41 }
42 qdf_export_symbol(qdf_list_insert_before);
43
qdf_list_insert_after(qdf_list_t * list,qdf_list_node_t * new_node,qdf_list_node_t * node)44 QDF_STATUS qdf_list_insert_after(qdf_list_t *list,
45 qdf_list_node_t *new_node, qdf_list_node_t *node)
46 {
47 list_add(new_node, node);
48 list->count++;
49
50 return QDF_STATUS_SUCCESS;
51 }
52 qdf_export_symbol(qdf_list_insert_after);
53
54 /**
55 * qdf_list_insert_front() - insert input node at front of the list
56 * @list: Pointer to list
57 * @node: Pointer to input node
58 *
59 * Return: QDF status
60 */
qdf_list_insert_front(qdf_list_t * list,qdf_list_node_t * node)61 QDF_STATUS qdf_list_insert_front(qdf_list_t *list, qdf_list_node_t *node)
62 {
63 list_add(node, &list->anchor);
64 list->count++;
65 return QDF_STATUS_SUCCESS;
66 }
67 qdf_export_symbol(qdf_list_insert_front);
68
69 /**
70 * qdf_list_insert_back() - insert input node at back of the list
71 * @list: Pointer to list
72 * @node: Pointer to input node
73 *
74 * Return: QDF status
75 */
qdf_list_insert_back(qdf_list_t * list,qdf_list_node_t * node)76 QDF_STATUS qdf_list_insert_back(qdf_list_t *list, qdf_list_node_t *node)
77 {
78 list_add_tail(node, &list->anchor);
79 list->count++;
80 return QDF_STATUS_SUCCESS;
81 }
82 qdf_export_symbol(qdf_list_insert_back);
83
84 /**
85 * qdf_list_insert_back_size() - insert input node at back of list and save
86 * list size
87 * @list: Pointer to list
88 * @node: Pointer to input node
89 * @p_size: Pointer to store list size
90 *
91 * Return: QDF status
92 */
qdf_list_insert_back_size(qdf_list_t * list,qdf_list_node_t * node,uint32_t * p_size)93 QDF_STATUS qdf_list_insert_back_size(qdf_list_t *list,
94 qdf_list_node_t *node, uint32_t *p_size)
95 {
96 list_add_tail(node, &list->anchor);
97 list->count++;
98 *p_size = list->count;
99 return QDF_STATUS_SUCCESS;
100 }
101 qdf_export_symbol(qdf_list_insert_back_size);
102
103 /**
104 * qdf_list_remove_front() - remove node from front of the list
105 * @list: Pointer to list
106 * @node2: Double pointer to store the node which is removed from list
107 *
108 * Return: QDF status
109 */
qdf_list_remove_front(qdf_list_t * list,qdf_list_node_t ** node2)110 QDF_STATUS qdf_list_remove_front(qdf_list_t *list, qdf_list_node_t **node2)
111 {
112 struct list_head *listptr;
113
114 if (list_empty(&list->anchor))
115 return QDF_STATUS_E_EMPTY;
116
117 listptr = list->anchor.next;
118 *node2 = listptr;
119 list_del_init(list->anchor.next);
120 list->count--;
121
122 return QDF_STATUS_SUCCESS;
123 }
124 qdf_export_symbol(qdf_list_remove_front);
125
126 /**
127 * qdf_list_remove_back() - remove node from end of the list
128 * @list: Pointer to list
129 * @node2: Double pointer to store node which is removed from list
130 *
131 * Return: QDF status
132 */
qdf_list_remove_back(qdf_list_t * list,qdf_list_node_t ** node2)133 QDF_STATUS qdf_list_remove_back(qdf_list_t *list, qdf_list_node_t **node2)
134 {
135 struct list_head *listptr;
136
137 if (list_empty(&list->anchor))
138 return QDF_STATUS_E_EMPTY;
139
140 listptr = list->anchor.prev;
141 *node2 = listptr;
142 list_del_init(list->anchor.prev);
143 list->count--;
144
145 return QDF_STATUS_SUCCESS;
146 }
147 qdf_export_symbol(qdf_list_remove_back);
148
qdf_list_has_node(qdf_list_t * list,qdf_list_node_t * node)149 bool qdf_list_has_node(qdf_list_t *list, qdf_list_node_t *node)
150 {
151 qdf_list_node_t *tmp;
152
153 list_for_each(tmp, &list->anchor) {
154 if (tmp == node)
155 return true;
156 }
157
158 return false;
159 }
160
161 /**
162 * qdf_list_remove_node() - remove input node from list
163 * @list: Pointer to list
164 * @node_to_remove: Pointer to node which needs to be removed
165 *
166 * verifies that the node is in the list before removing it.
167 * It is expected that the list being removed from is locked
168 * when this function is being called.
169 *
170 * Return: QDF status
171 */
qdf_list_remove_node(qdf_list_t * list,qdf_list_node_t * node_to_remove)172 QDF_STATUS qdf_list_remove_node(qdf_list_t *list,
173 qdf_list_node_t *node_to_remove)
174 {
175 if (list_empty(&list->anchor))
176 return QDF_STATUS_E_EMPTY;
177
178 list_del_init(node_to_remove);
179 list->count--;
180
181 return QDF_STATUS_SUCCESS;
182 }
183 qdf_export_symbol(qdf_list_remove_node);
184
185 /**
186 * qdf_list_peek_front() - peek front node from list
187 * @list: Pointer to list
188 * @node2: Double pointer to store peeked node pointer
189 *
190 * Return: QDF status
191 */
qdf_list_peek_front(qdf_list_t * list,qdf_list_node_t ** node2)192 QDF_STATUS qdf_list_peek_front(qdf_list_t *list, qdf_list_node_t **node2)
193 {
194 struct list_head *listptr;
195
196 if (list_empty(&list->anchor))
197 return QDF_STATUS_E_EMPTY;
198
199 listptr = list->anchor.next;
200 *node2 = listptr;
201
202 return QDF_STATUS_SUCCESS;
203 }
204 qdf_export_symbol(qdf_list_peek_front);
205
206 /**
207 * qdf_list_peek_next() - peek next node of input node in the list
208 * @list: Pointer to list
209 * @node: Pointer to input node
210 * @node2: Double pointer to store peeked node pointer
211 *
212 * Return: QDF status
213 */
qdf_list_peek_next(qdf_list_t * list,qdf_list_node_t * node,qdf_list_node_t ** node2)214 QDF_STATUS qdf_list_peek_next(qdf_list_t *list,
215 qdf_list_node_t *node,
216 qdf_list_node_t **node2)
217 {
218 if (!list || !node || !node2)
219 return QDF_STATUS_E_FAULT;
220
221 if (list_empty(&list->anchor))
222 return QDF_STATUS_E_EMPTY;
223
224 if (node->next == &list->anchor)
225 return QDF_STATUS_E_EMPTY;
226
227 *node2 = node->next;
228
229 return QDF_STATUS_SUCCESS;
230 }
231 qdf_export_symbol(qdf_list_peek_next);
232
233 /**
234 * qdf_list_empty() - check if the list is empty
235 * @list: pointer to the list
236 *
237 * Return: true if the list is empty and false otherwise.
238 */
qdf_list_empty(qdf_list_t * list)239 bool qdf_list_empty(qdf_list_t *list)
240 {
241 return list_empty(&list->anchor);
242 }
243 qdf_export_symbol(qdf_list_empty);
244
qdf_list_node_in_any_list(const qdf_list_node_t * node)245 bool qdf_list_node_in_any_list(const qdf_list_node_t *node)
246 {
247 const struct list_head *linux_node = (const struct list_head *)node;
248
249 if (!linux_node)
250 return false;
251
252 /* if the node is an empty list, it is not tied to an anchor node */
253 if (list_empty(linux_node))
254 return false;
255
256 if (!linux_node->prev || !linux_node->next)
257 return false;
258
259 if (linux_node->prev->next != linux_node ||
260 linux_node->next->prev != linux_node)
261 return false;
262
263 return true;
264 }
265
qdf_list_split(qdf_list_t * new,qdf_list_t * list,qdf_list_node_t * node)266 QDF_STATUS qdf_list_split(qdf_list_t *new, qdf_list_t *list,
267 qdf_list_node_t *node)
268 {
269 qdf_list_node_t *cur_node;
270 uint32_t new_list_count = 0;
271
272 list_cut_position(&new->anchor, &list->anchor, node);
273
274 list_for_each(cur_node, &new->anchor)
275 new_list_count++;
276
277 new->count = new_list_count;
278 list->count = list->count - new->count;
279
280 return QDF_STATUS_SUCCESS;
281 }
282
283 qdf_export_symbol(qdf_list_split);
284
qdf_list_join(qdf_list_t * list1,qdf_list_t * list2)285 QDF_STATUS qdf_list_join(qdf_list_t *list1, qdf_list_t *list2)
286 {
287 list_splice_tail_init(&list2->anchor, &list1->anchor);
288
289 list1->count = list1->count + list2->count;
290 list2->count = 0;
291
292 return QDF_STATUS_SUCCESS;
293 }
294
295 qdf_export_symbol(qdf_list_join);
296