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