1 /* 2 * Copyright (c) 2014-2018, 2021 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 QDF_STATUS qdf_list_split(qdf_list_t *new, qdf_list_t *list, 266 qdf_list_node_t *node) 267 { 268 qdf_list_node_t *cur_node; 269 uint32_t new_list_count = 0; 270 271 list_cut_position(&new->anchor, &list->anchor, node); 272 273 list_for_each(cur_node, &new->anchor) 274 new_list_count++; 275 276 new->count = new_list_count; 277 list->count = list->count - new->count; 278 279 return QDF_STATUS_SUCCESS; 280 } 281 282 qdf_export_symbol(qdf_list_split); 283 284 QDF_STATUS qdf_list_join(qdf_list_t *list1, qdf_list_t *list2) 285 { 286 list_splice_tail_init(&list2->anchor, &list1->anchor); 287 288 list1->count = list1->count + list2->count; 289 list2->count = 0; 290 291 return QDF_STATUS_SUCCESS; 292 } 293 294 qdf_export_symbol(qdf_list_join); 295