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