1 /* 2 * Copyright (c) 2013-2014, 2017, 2019 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 /* Double-link list definitions (adapted from Atheros SDIO stack) */ 22 /* */ 23 /* Author(s): ="Atheros" */ 24 /*=========================================================================== */ 25 26 #ifndef __DL_LIST_H___ 27 #define __DL_LIST_H___ 28 29 #include "qdf_util.h" 30 31 #define A_CONTAINING_STRUCT(address, struct_type, field_name) \ 32 (qdf_container_of(address, struct_type, field_name)) 33 34 /* list functions */ 35 /* pointers for the list */ 36 typedef struct _DL_LIST { 37 struct _DL_LIST *pPrev; 38 struct _DL_LIST *pNext; 39 } DL_LIST, *PDL_LIST; 40 /* 41 * DL_LIST_INIT , initialize doubly linked list 42 */ 43 #define DL_LIST_INIT(pList) \ 44 {(pList)->pPrev = pList; (pList)->pNext = pList; } 45 46 /* faster macro to init list and add a single item */ 47 #define DL_LIST_INIT_AND_ADD(pList, pItem) \ 48 { (pList)->pPrev = (pItem); \ 49 (pList)->pNext = (pItem); \ 50 (pItem)->pNext = (pList); \ 51 (pItem)->pPrev = (pList); \ 52 } 53 54 #define DL_LIST_IS_EMPTY(pList) (((pList)->pPrev == (pList)) && \ 55 ((pList)->pNext == (pList))) 56 #define DL_LIST_GET_ITEM_AT_HEAD(pList) (pList)->pNext 57 #define DL_LIST_GET_ITEM_AT_TAIL(pList) (pList)->pPrev 58 /* 59 * ITERATE_OVER_LIST pStart is the list, pTemp is a temp list member 60 * NOT: do not use this function if the items in the list are deleted inside the 61 * iteration loop 62 */ 63 #define ITERATE_OVER_LIST(pStart, pTemp) \ 64 for ((pTemp) = (pStart)->pNext; pTemp != (pStart); \ 65 (pTemp) = (pTemp)->pNext) 66 dl_list_is_entry_in_list(const DL_LIST * pList,const DL_LIST * pEntry)67 static inline bool dl_list_is_entry_in_list(const DL_LIST *pList, 68 const DL_LIST *pEntry) 69 { 70 const DL_LIST *pTmp; 71 72 if (pList == pEntry) 73 return true; 74 75 ITERATE_OVER_LIST(pList, pTmp) { 76 if (pTmp == pEntry) 77 return true; 78 } 79 80 return false; 81 } 82 83 /* safe iterate macro that allows the item to be removed from the list 84 * the iteration continues to the next item in the list 85 */ 86 #define ITERATE_OVER_LIST_ALLOW_REMOVE(pStart, pItem, st, offset) \ 87 { \ 88 PDL_LIST pTemp; \ 89 { pTemp = (pStart)->pNext; } \ 90 while (pTemp != (pStart)) { \ 91 { (pItem) = A_CONTAINING_STRUCT(pTemp, st, offset); } \ 92 { pTemp = pTemp->pNext; } \ 93 94 #define ITERATE_IS_VALID(pStart) dl_list_is_entry_in_list(pStart, pTemp) 95 #define ITERATE_RESET(pStart) { pTemp = (pStart)->pNext; } 96 97 #define ITERATE_END }} 98 99 /* 100 * dl_list_insert_tail - insert pAdd to the end of the list 101 */ dl_list_insert_tail(PDL_LIST pList,PDL_LIST pAdd)102 static inline PDL_LIST dl_list_insert_tail(PDL_LIST pList, PDL_LIST pAdd) 103 { 104 /* insert at tail */ 105 pAdd->pPrev = pList->pPrev; 106 pAdd->pNext = pList; 107 if (pList->pPrev) 108 pList->pPrev->pNext = pAdd; 109 pList->pPrev = pAdd; 110 return pAdd; 111 } 112 113 /* 114 * dl_list_insert_head - insert pAdd into the head of the list 115 */ dl_list_insert_head(PDL_LIST pList,PDL_LIST pAdd)116 static inline PDL_LIST dl_list_insert_head(PDL_LIST pList, PDL_LIST pAdd) 117 { 118 /* insert at head */ 119 pAdd->pPrev = pList; 120 pAdd->pNext = pList->pNext; 121 pList->pNext->pPrev = pAdd; 122 pList->pNext = pAdd; 123 return pAdd; 124 } 125 126 #define DL_ListAdd(pList, pItem) dl_list_insert_head((pList), (pItem)) 127 /* 128 * dl_list_remove - remove pDel from list 129 */ dl_list_remove(PDL_LIST pDel)130 static inline PDL_LIST dl_list_remove(PDL_LIST pDel) 131 { 132 if (pDel->pNext) 133 pDel->pNext->pPrev = pDel->pPrev; 134 if (pDel->pPrev) 135 pDel->pPrev->pNext = pDel->pNext; 136 /* point back to itself just to be safe, if remove is called again */ 137 pDel->pNext = pDel; 138 pDel->pPrev = pDel; 139 return pDel; 140 } 141 142 /* 143 * dl_list_remove_item_from_head - get a list item from the head 144 */ dl_list_remove_item_from_head(PDL_LIST pList)145 static inline PDL_LIST dl_list_remove_item_from_head(PDL_LIST pList) 146 { 147 PDL_LIST pItem = NULL; 148 149 if (pList->pNext != pList) { 150 pItem = pList->pNext; 151 /* remove the first item from head */ 152 dl_list_remove(pItem); 153 } 154 return pItem; 155 } 156 dl_list_remove_item_from_tail(PDL_LIST pList)157 static inline PDL_LIST dl_list_remove_item_from_tail(PDL_LIST pList) 158 { 159 PDL_LIST pItem = NULL; 160 161 if (pList->pPrev != pList) { 162 pItem = pList->pPrev; 163 /* remove the item from tail */ 164 dl_list_remove(pItem); 165 } 166 return pItem; 167 } 168 169 /* transfer src list items to the tail of the destination list */ dl_list_transfer_items_to_tail(PDL_LIST pDest,PDL_LIST pSrc)170 static inline void dl_list_transfer_items_to_tail(PDL_LIST pDest, PDL_LIST pSrc) 171 { 172 /* only concatenate if src is not empty */ 173 if (!DL_LIST_IS_EMPTY(pSrc)) { 174 /* cut out circular list in src and re-attach to end of dest */ 175 pSrc->pPrev->pNext = pDest; 176 pSrc->pNext->pPrev = pDest->pPrev; 177 pDest->pPrev->pNext = pSrc->pNext; 178 pDest->pPrev = pSrc->pPrev; 179 /* terminate src list, it is now empty */ 180 pSrc->pPrev = pSrc; 181 pSrc->pNext = pSrc; 182 } 183 } 184 185 /* transfer src list items to the head of the destination list */ dl_list_transfer_items_to_head(PDL_LIST pDest,PDL_LIST pSrc)186 static inline void dl_list_transfer_items_to_head(PDL_LIST pDest, PDL_LIST pSrc) 187 { 188 /* only concatenate if src is not empty */ 189 if (!DL_LIST_IS_EMPTY(pSrc)) { 190 /* cut out circular list in src and reattach to start of dest */ 191 pSrc->pNext->pPrev = pDest; 192 pDest->pNext->pPrev = pSrc->pPrev; 193 pSrc->pPrev->pNext = pDest->pNext; 194 pDest->pNext = pSrc->pNext; 195 /* terminate src list, it is now empty */ 196 pSrc->pPrev = pSrc; 197 pSrc->pNext = pSrc; 198 } 199 } 200 201 #endif /* __DL_LIST_H___ */ 202