blob: 74d940f4f1cce3530ecfcc6e52ca2e578251126d [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Jeff Johnson32d95a32012-09-10 13:15:23 -07002 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -07003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/** ------------------------------------------------------------------------- *
23 ------------------------------------------------------------------------- *
24 \file csrLinkList.c
25
26 Implementation for the Common link list interfaces.
27
28
29 Copyright (C) 2006 Airgo Networks, Incorporated
30 ========================================================================== */
31
32#include "palApi.h"
33#include "csrLinkList.h"
34#include "vos_lock.h"
35#include "vos_memory.h"
36#include "vos_trace.h"
37
38ANI_INLINE_FUNCTION void csrListInit(tListElem *pList)
39{
40 pList->last = pList->next = pList;
41}
42
43
44ANI_INLINE_FUNCTION void csrListRemoveEntry(tListElem *pEntry)
45{
46 tListElem *pLast;
47 tListElem *pNext;
48
49 pLast = pEntry->last;
50 pNext = pEntry->next;
51 pLast->next = pNext;
52 pNext->last = pLast;
53}
54
55
56ANI_INLINE_FUNCTION tListElem * csrListRemoveHead(tListElem *pHead)
57{
58 tListElem *pEntry;
59 tListElem *pNext;
60
61 pEntry = pHead->next;
62 pNext = pEntry->next;
63 pHead->next = pNext;
64 pNext->last = pHead;
65
66 return (pEntry);
67}
68
69
70
71ANI_INLINE_FUNCTION tListElem * csrListRemoveTail(tListElem *pHead)
72{
73 tListElem *pEntry;
74 tListElem *pLast;
75
76 pEntry = pHead->last;
77 pLast = pEntry->last;
78 pHead->last = pLast;
79 pLast->next = pHead;
80
81 return (pEntry);
82}
83
84
85ANI_INLINE_FUNCTION void csrListInsertTail(tListElem *pHead, tListElem *pEntry)
86{
87 tListElem *pLast;
88
89 pLast = pHead->last;
90 pEntry->last = pLast;
91 pEntry->next = pHead;
92 pLast->next = pEntry;
93 pHead->last = pEntry;
94}
95
96
97ANI_INLINE_FUNCTION void csrListInsertHead(tListElem *pHead, tListElem *pEntry)
98{
99 tListElem *pNext;
100
101 pNext = pHead->next;
102 pEntry->next = pNext;
103 pEntry->last = pHead;
104 pNext->last = pEntry;
105 pHead->next = pEntry;
106}
107
108
109//Insert pNewEntry before pEntry
110void csrListInsertEntry(tListElem *pEntry, tListElem *pNewEntry)
111{
112 tListElem *pLast;
113 if( !pEntry)
114 {
115 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pEntry is Null", __FUNCTION__);
116 return;
117 }
118
119 pLast = pEntry->last;
120 pLast->next = pNewEntry;
121 pEntry->last = pNewEntry;
122 pNewEntry->next = pEntry;
123 pNewEntry->last = pLast;
124}
125
126tANI_U32 csrLLCount( tDblLinkList *pList )
127{
128 tANI_U32 c = 0;
129
130
131 if( !pList)
132 {
133 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
134 return c;
135 }
136
137 if ( pList && ( LIST_FLAG_OPEN == pList->Flag ) )
138 {
139 c = pList->Count;
140 }
141
142 return( c );
143}
144
145
146void csrLLLock( tDblLinkList *pList )
147{
148
149
150 if( !pList)
151 {
152 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
153 return ;
154 }
155
156 if ( LIST_FLAG_OPEN == pList->Flag )
157 {
158 vos_lock_acquire(&pList->Lock);
159 }
160}
161
162
163void csrLLUnlock( tDblLinkList *pList )
164{
165
166 if( !pList)
167 {
168 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
169 return ;
170 }
171
172 if ( LIST_FLAG_OPEN == pList->Flag )
173 {
174 vos_lock_release(&pList->Lock);
175 }
176}
177
178
179tANI_BOOLEAN csrLLIsListEmpty( tDblLinkList *pList, tANI_BOOLEAN fInterlocked )
180{
181 tANI_BOOLEAN fEmpty = eANI_BOOLEAN_TRUE;
182
183
184 if( !pList)
185 {
186 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
187 return fEmpty ;
188 }
189
190 if ( LIST_FLAG_OPEN == pList->Flag )
191 {
192 if(fInterlocked)
193 {
194 csrLLLock(pList);
195 }
196
197 fEmpty = csrIsListEmpty( &pList->ListHead );
198
199 if(fInterlocked)
200 {
201 csrLLUnlock(pList);
202 }
203 }
204 return( fEmpty );
205}
206
207
208
209tANI_BOOLEAN csrLLFindEntry( tDblLinkList *pList, tListElem *pEntryToFind )
210{
211 tANI_BOOLEAN fFound = eANI_BOOLEAN_FALSE;
212 tListElem *pEntry;
213
214
215 if( !pList)
216 {
217 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
218 return fFound ;
219 }
220
221 if ( LIST_FLAG_OPEN == pList->Flag )
222 {
223 pEntry = csrLLPeekHead( pList, LL_ACCESS_NOLOCK);
224
225 // Have to make sure we don't loop back to the head of the list, which will
226 // happen if the entry is NOT on the list...
227
228 while( pEntry && ( pEntry != &pList->ListHead ) )
229 {
230 if ( pEntry == pEntryToFind )
231 {
232 fFound = eANI_BOOLEAN_TRUE;
233 break;
234 }
235 pEntry = pEntry->next;
236 }
237
238 }
239 return( fFound );
240}
241
242
243eHalStatus csrLLOpen( tHddHandle hHdd, tDblLinkList *pList )
244{
245 eHalStatus status = eHAL_STATUS_SUCCESS;
246 VOS_STATUS vosStatus;
247
248 if( !pList)
249 {
250 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
251 return eHAL_STATUS_FAILURE ;
252 }
253
254 if ( LIST_FLAG_OPEN != pList->Flag )
255 {
256 pList->Count = 0;
257
258 vosStatus = vos_lock_init(&pList->Lock);
259
260 if(VOS_IS_STATUS_SUCCESS(vosStatus))
261 {
262 csrListInit( &pList->ListHead );
263 pList->Flag = LIST_FLAG_OPEN;
264 pList->hHdd = hHdd;
265 }
266 else
267 {
268 status = eHAL_STATUS_FAILURE;
269 }
270 }
271 return (status);
272}
273
274void csrLLClose( tDblLinkList *pList )
275{
276 if( !pList)
277 {
278 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
279 return ;
280 }
281
282 if ( LIST_FLAG_OPEN == pList->Flag )
283 {
284 // Make sure the list is empty...
285 csrLLPurge( pList, LL_ACCESS_LOCK );
286 vos_lock_destroy( &pList->Lock );
287 pList->Flag = LIST_FLAG_CLOSE;
288 }
289}
290
291void csrLLInsertTail( tDblLinkList *pList, tListElem *pEntry, tANI_BOOLEAN fInterlocked )
292{
293 if( !pList)
294 {
295 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
296 return;
297 }
298
299 if ( LIST_FLAG_OPEN == pList->Flag )
300 {
301 if(fInterlocked)
302 {
303 csrLLLock(pList);
304 }
305 csrListInsertTail( &pList->ListHead, pEntry );
306 pList->Count++;
307 if(fInterlocked)
308 {
309 csrLLUnlock(pList);
310 }
311 }
312}
313
314
315
316void csrLLInsertHead( tDblLinkList *pList, tListElem *pEntry, tANI_BOOLEAN fInterlocked )
317{
318
319 if( !pList)
320 {
321 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
322 return;
323 }
324
325 if ( LIST_FLAG_OPEN == pList->Flag )
326 {
327 if(fInterlocked)
328 {
329 csrLLLock(pList);
330 }
331 csrListInsertHead( &pList->ListHead, pEntry );
332 pList->Count++;
333 if(fInterlocked)
334 {
335 csrLLUnlock(pList);
336 }
337 }
338}
339
340
341void csrLLInsertEntry( tDblLinkList *pList, tListElem *pEntry, tListElem *pNewEntry, tANI_BOOLEAN fInterlocked )
342{
343 if( !pList)
344 {
345 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
346 return ;
347 }
348
349 if ( LIST_FLAG_OPEN == pList->Flag )
350 {
351 if(fInterlocked)
352 {
353 csrLLLock(pList);
354 }
355 csrListInsertEntry( pEntry, pNewEntry );
356 pList->Count++;
357 if(fInterlocked)
358 {
359 csrLLUnlock(pList);
360 }
361 }
362}
363
364
365
366tListElem *csrLLRemoveTail( tDblLinkList *pList, tANI_BOOLEAN fInterlocked )
367{
368 tListElem *pEntry = NULL;
369
370 if( !pList)
371 {
372 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
373 return pEntry ;
374 }
375
376 if ( LIST_FLAG_OPEN == pList->Flag )
377 {
378 if ( fInterlocked )
379 {
380 csrLLLock( pList );
381 }
382
383 if ( !csrIsListEmpty(&pList->ListHead) )
384 {
385
386 pEntry = csrListRemoveTail( &pList->ListHead );
387 pList->Count--;
388 }
389 if ( fInterlocked )
390 {
391 csrLLUnlock( pList );
392 }
393 }
394
395 return( pEntry );
396}
397
398
399tListElem *csrLLPeekTail( tDblLinkList *pList, tANI_BOOLEAN fInterlocked )
400{
401 tListElem *pEntry = NULL;
402
403
404 if( !pList)
405 {
406 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
407 return pEntry ;
408 }
409
410 if ( LIST_FLAG_OPEN == pList->Flag )
411 {
412 if ( fInterlocked )
413 {
414 csrLLLock( pList );
415 }
416
417 if ( !csrIsListEmpty(&pList->ListHead) )
418 {
419 pEntry = pList->ListHead.last;
420 }
421 if ( fInterlocked )
422 {
423 csrLLUnlock( pList );
424 }
425 }
426
427 return( pEntry );
428}
429
430
431
432tListElem *csrLLRemoveHead( tDblLinkList *pList, tANI_BOOLEAN fInterlocked )
433{
434 tListElem *pEntry = NULL;
435
436
437 if( !pList)
438 {
439 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
440 return pEntry ;
441 }
442
443 if ( LIST_FLAG_OPEN == pList->Flag )
444 {
445 if ( fInterlocked )
446 {
447 csrLLLock( pList );
448 }
449
450 if ( !csrIsListEmpty(&pList->ListHead) )
451 {
452 pEntry = csrListRemoveHead( &pList->ListHead );
453 pList->Count--;
454 }
455
456 if ( fInterlocked )
457 {
458 csrLLUnlock( pList );
459 }
460 }
461
462 return( pEntry );
463}
464
465
466tListElem *csrLLPeekHead( tDblLinkList *pList, tANI_BOOLEAN fInterlocked )
467{
468 tListElem *pEntry = NULL;
469
470 if( !pList)
471 {
472 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
473 return pEntry ;
474 }
475
476 if ( LIST_FLAG_OPEN == pList->Flag )
477 {
478 if ( fInterlocked )
479 {
480 csrLLLock( pList );
481 }
482
483 if ( !csrIsListEmpty(&pList->ListHead) )
484 {
485 pEntry = pList->ListHead.next;
486 }
487 if ( fInterlocked )
488 {
489 csrLLUnlock( pList );
490 }
491 }
492
493 return( pEntry );
494}
495
496
497
498void csrLLPurge( tDblLinkList *pList, tANI_BOOLEAN fInterlocked )
499{
500 tListElem *pEntry;
501
502 if( !pList)
503 {
504 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
505 return ;
506 }
507
508 if ( LIST_FLAG_OPEN == pList->Flag )
509 {
510 if ( fInterlocked )
511 {
512 csrLLLock( pList );
513 }
514 while( (pEntry = csrLLRemoveHead( pList, LL_ACCESS_NOLOCK )) )
515 {
516 // just remove everything from the list until
517 // nothing left on the list.
518 }
519 if ( fInterlocked )
520 {
521 csrLLUnlock( pList );
522 }
523 }
524}
525
526
527tANI_BOOLEAN csrLLRemoveEntry( tDblLinkList *pList, tListElem *pEntryToRemove, tANI_BOOLEAN fInterlocked )
528{
529 tANI_BOOLEAN fFound = eANI_BOOLEAN_FALSE;
530 tListElem *pEntry;
531
532 if( !pList)
533 {
534 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
535 return fFound;
536 }
537
538 if ( LIST_FLAG_OPEN == pList->Flag )
539 {
540 if ( fInterlocked )
541 {
542 csrLLLock( pList );
543 }
544
545 pEntry = csrLLPeekHead( pList, LL_ACCESS_NOLOCK );
546
547 // Have to make sure we don't loop back to the head of the list, which will
548 // happen if the entry is NOT on the list...
549 while( pEntry && ( pEntry != &pList->ListHead ) )
550 {
551 if ( pEntry == pEntryToRemove )
552 {
553 csrListRemoveEntry( pEntry );
554 pList->Count--;
555
556 fFound = eANI_BOOLEAN_TRUE;
557 break;
558 }
559
560 pEntry = pEntry->next;
561 }
562 if ( fInterlocked )
563 {
564 csrLLUnlock( pList );
565 }
566 }
567
568 return( fFound );
569}
570
571
572
573tListElem *csrLLNext( tDblLinkList *pList, tListElem *pEntry, tANI_BOOLEAN fInterlocked )
574{
575 tListElem *pNextEntry = NULL;
576
577 if( !pList)
578 {
579 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
580 return pNextEntry ;
581 }
582
583 if ( LIST_FLAG_OPEN == pList->Flag )
584 {
585 if ( fInterlocked )
586 {
587 csrLLLock( pList );
588 }
589
590 if ( !csrIsListEmpty(&pList->ListHead) && csrLLFindEntry( pList, pEntry ) )
591 {
592 pNextEntry = pEntry->next;
593 //Make sure we don't walk past the head
594 if ( pNextEntry == &pList->ListHead )
595 {
596 pNextEntry = NULL;
597 }
598 }
599
600 if ( fInterlocked )
601 {
602 csrLLUnlock( pList );
603 }
604 }
605
606 return( pNextEntry );
607}
608
609
610tListElem *csrLLPrevious( tDblLinkList *pList, tListElem *pEntry, tANI_BOOLEAN fInterlocked )
611{
612 tListElem *pNextEntry = NULL;
613
614 if( !pList)
615 {
616 VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,"%s: Error!! pList is Null", __FUNCTION__);
617 return pNextEntry ;
618 }
619
620 if ( LIST_FLAG_OPEN == pList->Flag )
621 {
622 if ( fInterlocked )
623 {
624 csrLLLock( pList );
625 }
626
627 if ( !csrIsListEmpty(&pList->ListHead) && csrLLFindEntry( pList, pEntry ) )
628 {
629 pNextEntry = pEntry->last;
630 //Make sure we don't walk past the head
631 if ( pNextEntry == &pList->ListHead )
632 {
633 pNextEntry = NULL;
634 }
635 }
636
637 if ( fInterlocked )
638 {
639 csrLLUnlock( pList );
640 }
641 }
642
643 return( pNextEntry );
644}
645
646
647
648