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