xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/hnd_pktq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * HND generic pktq operation primitives
3  *
4  * Copyright (C) 2020, Broadcom.
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *
21  * <<Broadcom-WL-IPTag/Dual:>>
22  */
23 
24 #include <typedefs.h>
25 #include <osl.h>
26 #include <osl_ext.h>
27 #include <bcmutils.h>
28 #include <hnd_pktq.h>
29 
30 /* mutex macros for thread safe */
31 #ifdef HND_PKTQ_THREAD_SAFE
32 #define HND_PKTQ_MUTEX_CREATE(name, mutex)	osl_ext_mutex_create(name, mutex)
33 #define HND_PKTQ_MUTEX_DELETE(mutex)		osl_ext_mutex_delete(mutex)
34 #define HND_PKTQ_MUTEX_ACQUIRE(mutex, msec)	osl_ext_mutex_acquire(mutex, msec)
35 #define HND_PKTQ_MUTEX_RELEASE(mutex)		osl_ext_mutex_release(mutex)
36 #else
37 #define HND_PKTQ_MUTEX_CREATE(name, mutex)	OSL_EXT_SUCCESS
38 #define HND_PKTQ_MUTEX_DELETE(mutex)		OSL_EXT_SUCCESS
39 #define HND_PKTQ_MUTEX_ACQUIRE(mutex, msec)	OSL_EXT_SUCCESS
40 #define HND_PKTQ_MUTEX_RELEASE(mutex)		OSL_EXT_SUCCESS
41 #endif /* HND_PKTQ_THREAD_SAFE */
42 
43 /* status during txfifo sync */
44 #if defined(PROP_TXSTATUS)
45 #define TXQ_PKT_DEL		0x01
46 #define HEAD_PKT_FLUSHED	0xFF
47 #endif /* defined(PROP_TXSTATUS) */
48 /*
49  * osl multiple-precedence packet queue
50  * hi_prec is always >= the number of the highest non-empty precedence
51  */
52 void *
BCMFASTPATH(pktq_penq)53 BCMFASTPATH(pktq_penq)(struct pktq *pq, int prec, void *p)
54 {
55 	struct pktq_prec *q;
56 
57 	/* protect shared resource */
58 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
59 		return NULL;
60 
61 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
62 	ASSERT_FP(PKTLINK(p) == NULL);		/* queueing chains not allowed */
63 
64 	ASSERT_FP(!pktq_full(pq));
65 	ASSERT_FP(!pktqprec_full(pq, prec));
66 
67 	q = &pq->q[prec];
68 
69 	if (q->head)
70 		PKTSETLINK(q->tail, p);
71 	else
72 		q->head = p;
73 
74 	q->tail = p;
75 	q->n_pkts++;
76 
77 	pq->n_pkts_tot++;
78 
79 	if (pq->hi_prec < prec)
80 		pq->hi_prec = (uint8)prec;
81 
82 	/* protect shared resource */
83 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
84 		return NULL;
85 
86 	return p;
87 }
88 
89 void *
BCMFASTPATH(spktq_enq_chain)90 BCMFASTPATH(spktq_enq_chain)(struct spktq *dspq, struct spktq *sspq)
91 {
92 	struct pktq_prec *dq;
93 	struct pktq_prec *sq;
94 
95 	/* protect shared resource */
96 	if (HND_PKTQ_MUTEX_ACQUIRE(&dspq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
97 		return NULL;
98 
99 	/* protect shared resource */
100 	if (HND_PKTQ_MUTEX_ACQUIRE(&sspq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
101 		return NULL;
102 
103 	dq = &dspq->q;
104 	sq = &sspq->q;
105 
106 	if (dq->head) {
107 		PKTSETLINK(OSL_PHYS_TO_VIRT_ADDR(dq->tail), OSL_VIRT_TO_PHYS_ADDR(sq->head));
108 	}
109 	else {
110 		dq->head = sq->head;
111 	}
112 
113 	dq->tail = sq->tail;
114 	dq->n_pkts += sq->n_pkts;
115 
116 	/* protect shared resource */
117 	if (HND_PKTQ_MUTEX_RELEASE(&dspq->mutex) != OSL_EXT_SUCCESS)
118 		return NULL;
119 
120 	/* protect shared resource */
121 	if (HND_PKTQ_MUTEX_RELEASE(&sspq->mutex) != OSL_EXT_SUCCESS)
122 		return NULL;
123 
124 	return dspq;
125 }
126 
127 /*
128  * osl simple, non-priority packet queue
129  */
130 void *
BCMFASTPATH(spktq_enq)131 BCMFASTPATH(spktq_enq)(struct spktq *spq, void *p)
132 {
133 	struct pktq_prec *q;
134 
135 	/* protect shared resource */
136 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
137 		return NULL;
138 
139 	ASSERT_FP(!spktq_full(spq));
140 
141 	PKTSETLINK(p, NULL);
142 
143 	q = &spq->q;
144 
145 	if (q->head)
146 		PKTSETLINK(q->tail, p);
147 	else
148 		q->head = p;
149 
150 	q->tail = p;
151 	q->n_pkts++;
152 
153 	/* protect shared resource */
154 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
155 		return NULL;
156 
157 	return p;
158 }
159 
160 void *
BCMPOSTTRAPFASTPATH(pktq_penq_head)161 BCMPOSTTRAPFASTPATH(pktq_penq_head)(struct pktq *pq, int prec, void *p)
162 {
163 	struct pktq_prec *q;
164 
165 	/* protect shared resource */
166 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
167 		return NULL;
168 
169 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
170 	ASSERT_FP(PKTLINK(p) == NULL);		/* queueing chains not allowed */
171 
172 	ASSERT_FP(!pktq_full(pq));
173 	ASSERT_FP(!pktqprec_full(pq, prec));
174 
175 	q = &pq->q[prec];
176 
177 	if (q->head == NULL)
178 		q->tail = p;
179 
180 	PKTSETLINK(p, q->head);
181 	q->head = p;
182 	q->n_pkts++;
183 
184 	pq->n_pkts_tot++;
185 
186 	if (pq->hi_prec < prec)
187 		pq->hi_prec = (uint8)prec;
188 
189 	/* protect shared resource */
190 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
191 		return NULL;
192 
193 	return p;
194 }
195 
196 void *
BCMFASTPATH(spktq_enq_head)197 BCMFASTPATH(spktq_enq_head)(struct spktq *spq, void *p)
198 {
199 	struct pktq_prec *q;
200 
201 	/* protect shared resource */
202 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
203 		return NULL;
204 
205 	ASSERT_FP(!spktq_full(spq));
206 
207 	PKTSETLINK(p, NULL);
208 
209 	q = &spq->q;
210 
211 	if (q->head == NULL)
212 		q->tail = p;
213 
214 	PKTSETLINK(p, q->head);
215 	q->head = p;
216 	q->n_pkts++;
217 
218 	/* protect shared resource */
219 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
220 		return NULL;
221 
222 	return p;
223 }
224 
225 void *
BCMFASTPATH(pktq_pdeq)226 BCMFASTPATH(pktq_pdeq)(struct pktq *pq, int prec)
227 {
228 	struct pktq_prec *q;
229 	void *p;
230 
231 	/* protect shared resource */
232 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
233 		return NULL;
234 
235 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
236 
237 	q = &pq->q[prec];
238 
239 	if ((p = q->head) == NULL)
240 		goto done;
241 
242 	if ((q->head = PKTLINK(p)) == NULL)
243 		q->tail = NULL;
244 
245 	q->n_pkts--;
246 
247 	pq->n_pkts_tot--;
248 
249 #ifdef WL_TXQ_STALL
250 	q->dequeue_count++;
251 #endif
252 
253 	PKTSETLINK(p, NULL);
254 
255 done:
256 	/* protect shared resource */
257 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
258 		return NULL;
259 
260 	return p;
261 }
262 
263 void *
BCMFASTPATH(spktq_deq)264 BCMFASTPATH(spktq_deq)(struct spktq *spq)
265 {
266 	struct pktq_prec *q;
267 	void *p;
268 
269 	/* protect shared resource */
270 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
271 		return NULL;
272 
273 	q = &spq->q;
274 
275 	if ((p = q->head) == NULL)
276 		goto done;
277 
278 	if ((q->head = PKTLINK(p)) == NULL)
279 		q->tail = NULL;
280 
281 	q->n_pkts--;
282 
283 #ifdef WL_TXQ_STALL
284 	q->dequeue_count++;
285 #endif
286 
287 	PKTSETLINK(p, NULL);
288 
289 done:
290 	/* protect shared resource */
291 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
292 		return NULL;
293 
294 	return p;
295 }
296 
297 void*
BCMFASTPATH(spktq_deq_virt)298 BCMFASTPATH(spktq_deq_virt)(struct spktq *spq)
299 {
300 	struct pktq_prec *q;
301 	void *p;
302 
303 	/* protect shared resource */
304 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
305 		return NULL;
306 
307 	q = &spq->q;
308 
309 	if ((p = q->head) == NULL)
310 		goto done;
311 
312 	p = (void *)OSL_PHYS_TO_VIRT_ADDR(p);
313 
314 	if ((q->head = (void*)PKTLINK(p)) == NULL)
315 		q->tail = NULL;
316 
317 	q->n_pkts--;
318 
319 #ifdef WL_TXQ_STALL
320 	q->dequeue_count++;
321 #endif
322 
323 	PKTSETLINK(p, NULL);
324 
325 done:
326 	/* protect shared resource */
327 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
328 		return NULL;
329 
330 	return p;
331 }
332 
333 void *
BCMFASTPATH(pktq_pdeq_tail)334 BCMFASTPATH(pktq_pdeq_tail)(struct pktq *pq, int prec)
335 {
336 	struct pktq_prec *q;
337 	void *p, *prev;
338 
339 	/* protect shared resource */
340 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
341 		return NULL;
342 
343 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
344 
345 	q = &pq->q[prec];
346 
347 	if ((p = q->head) == NULL)
348 		goto done;
349 
350 	for (prev = NULL; p != q->tail; p = PKTLINK(p))
351 		prev = p;
352 
353 	if (prev)
354 		PKTSETLINK(prev, NULL);
355 	else
356 		q->head = NULL;
357 
358 	q->tail = prev;
359 	q->n_pkts--;
360 
361 	pq->n_pkts_tot--;
362 
363 #ifdef WL_TXQ_STALL
364 	q->dequeue_count++;
365 #endif
366 done:
367 	/* protect shared resource */
368 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
369 		return NULL;
370 
371 	return p;
372 }
373 
374 void *
BCMFASTPATH(spktq_deq_tail)375 BCMFASTPATH(spktq_deq_tail)(struct spktq *spq)
376 {
377 	struct pktq_prec *q;
378 	void *p, *prev;
379 
380 	/* protect shared resource */
381 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
382 		return NULL;
383 
384 	q = &spq->q;
385 
386 	if ((p = q->head) == NULL)
387 		goto done;
388 
389 	for (prev = NULL; p != q->tail; p = PKTLINK(p))
390 		prev = p;
391 
392 	if (prev)
393 		PKTSETLINK(prev, NULL);
394 	else
395 		q->head = NULL;
396 
397 	q->tail = prev;
398 	q->n_pkts--;
399 
400 #ifdef WL_TXQ_STALL
401 	q->dequeue_count++;
402 #endif
403 done:
404 	/* protect shared resource */
405 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
406 		return NULL;
407 
408 	return p;
409 }
410 
411 void *
pktq_peek_tail(struct pktq * pq,int * prec_out)412 pktq_peek_tail(struct pktq *pq, int *prec_out)
413 {
414 	int prec;
415 	void *p = NULL;
416 
417 	/* protect shared resource */
418 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
419 		return NULL;
420 
421 	if (pq->n_pkts_tot == 0)
422 		goto done;
423 
424 	for (prec = 0; prec < pq->hi_prec; prec++)
425 		if (pq->q[prec].head)
426 			break;
427 
428 	if (prec_out)
429 		*prec_out = prec;
430 
431 	p = pq->q[prec].tail;
432 
433 done:
434 	/* protect shared resource */
435 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
436 		return NULL;
437 
438 	return p;
439 }
440 
441 /*
442  * Append spktq 'list' to the tail of pktq 'pq'
443  */
444 void
BCMFASTPATH(pktq_append)445 BCMFASTPATH(pktq_append)(struct pktq *pq, int prec, struct spktq *list)
446 {
447 	struct pktq_prec *q;
448 	struct pktq_prec *list_q;
449 
450 	/* protect shared resource */
451 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
452 		return;
453 
454 	list_q = &list->q;
455 
456 	/* empty list check */
457 	if (list_q->head == NULL)
458 		goto done;
459 
460 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
461 	ASSERT_FP(PKTLINK(list_q->tail) == NULL);         /* terminated list */
462 
463 	ASSERT_FP(!pktq_full(pq));
464 	ASSERT_FP(!pktqprec_full(pq, prec));
465 
466 	q = &pq->q[prec];
467 
468 	if (q->head)
469 		PKTSETLINK(q->tail, list_q->head);
470 	else
471 		q->head = list_q->head;
472 
473 	q->tail = list_q->tail;
474 	q->n_pkts += list_q->n_pkts;
475 	pq->n_pkts_tot += list_q->n_pkts;
476 
477 	if (pq->hi_prec < prec)
478 		pq->hi_prec = (uint8)prec;
479 
480 #ifdef WL_TXQ_STALL
481 	list_q->dequeue_count += list_q->n_pkts;
482 #endif
483 
484 	list_q->head = NULL;
485 	list_q->tail = NULL;
486 	list_q->n_pkts = 0;
487 
488 done:
489 	/* protect shared resource */
490 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
491 		return;
492 }
493 
494 /*
495  * Append spktq 'list' to the tail of spktq 'spq'
496  */
497 void
BCMFASTPATH(spktq_append)498 BCMFASTPATH(spktq_append)(struct spktq *spq, struct spktq *list)
499 {
500 	struct pktq_prec *q;
501 	struct pktq_prec *list_q;
502 
503 	/* protect shared resource */
504 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
505 		return;
506 
507 	list_q = &list->q;
508 
509 	/* empty list check */
510 	if (list_q->head == NULL)
511 		goto done;
512 
513 	ASSERT_FP(PKTLINK(list_q->tail) == NULL);         /* terminated list */
514 
515 	ASSERT_FP(!spktq_full(spq));
516 
517 	q = &spq->q;
518 
519 	if (q->head)
520 		PKTSETLINK(q->tail, list_q->head);
521 	else
522 		q->head = list_q->head;
523 
524 	q->tail = list_q->tail;
525 	q->n_pkts += list_q->n_pkts;
526 
527 #ifdef WL_TXQ_STALL
528 	list_q->dequeue_count += list_q->n_pkts;
529 #endif
530 
531 	list_q->head = NULL;
532 	list_q->tail = NULL;
533 	list_q->n_pkts = 0;
534 
535 done:
536 	/* protect shared resource */
537 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
538 		return;
539 }
540 
541 /*
542  * Prepend spktq 'list' to the head of pktq 'pq'
543  */
544 void
BCMFASTPATH(pktq_prepend)545 BCMFASTPATH(pktq_prepend)(struct pktq *pq, int prec, struct spktq *list)
546 {
547 	struct pktq_prec *q;
548 	struct pktq_prec *list_q;
549 
550 	/* protect shared resource */
551 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
552 		return;
553 
554 	list_q = &list->q;
555 
556 	/* empty list check */
557 	if (list_q->head == NULL)
558 		goto done;
559 
560 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
561 	ASSERT_FP(PKTLINK(list_q->tail) == NULL);         /* terminated list */
562 
563 	ASSERT_FP(!pktq_full(pq));
564 	ASSERT_FP(!pktqprec_full(pq, prec));
565 
566 	q = &pq->q[prec];
567 
568 	/* set the tail packet of list to point at the former pq head */
569 	PKTSETLINK(list_q->tail, q->head);
570 	/* the new q head is the head of list */
571 	q->head = list_q->head;
572 
573 	/* If the q tail was non-null, then it stays as is.
574 	 * If the q tail was null, it is now the tail of list
575 	 */
576 	if (q->tail == NULL) {
577 		q->tail = list_q->tail;
578 	}
579 
580 	q->n_pkts += list_q->n_pkts;
581 	pq->n_pkts_tot += list_q->n_pkts;
582 
583 	if (pq->hi_prec < prec)
584 		pq->hi_prec = (uint8)prec;
585 
586 #ifdef WL_TXQ_STALL
587 	list_q->dequeue_count += list_q->n_pkts;
588 #endif
589 
590 	list_q->head = NULL;
591 	list_q->tail = NULL;
592 	list_q->n_pkts = 0;
593 
594 done:
595 	/* protect shared resource */
596 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
597 		return;
598 }
599 
600 /*
601  * Prepend spktq 'list' to the head of spktq 'spq'
602  */
603 void
BCMFASTPATH(spktq_prepend)604 BCMFASTPATH(spktq_prepend)(struct spktq *spq, struct spktq *list)
605 {
606 	struct pktq_prec *q;
607 	struct pktq_prec *list_q;
608 
609 	/* protect shared resource */
610 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
611 		return;
612 
613 	list_q = &list->q;
614 
615 	/* empty list check */
616 	if (list_q->head == NULL)
617 		goto done;
618 
619 	ASSERT_FP(PKTLINK(list_q->tail) == NULL);         /* terminated list */
620 
621 	ASSERT_FP(!spktq_full(spq));
622 
623 	q = &spq->q;
624 
625 	/* set the tail packet of list to point at the former pq head */
626 	PKTSETLINK(list_q->tail, q->head);
627 	/* the new q head is the head of list */
628 	q->head = list_q->head;
629 
630 	/* If the q tail was non-null, then it stays as is.
631 	 * If the q tail was null, it is now the tail of list
632 	 */
633 	if (q->tail == NULL) {
634 		q->tail = list_q->tail;
635 	}
636 
637 	q->n_pkts += list_q->n_pkts;
638 
639 #ifdef WL_TXQ_STALL
640 	list_q->dequeue_count += list_q->n_pkts;
641 #endif
642 
643 	list_q->head = NULL;
644 	list_q->tail = NULL;
645 	list_q->n_pkts = 0;
646 
647 done:
648 	/* protect shared resource */
649 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
650 		return;
651 }
652 
653 void *
BCMFASTPATH(pktq_pdeq_prev)654 BCMFASTPATH(pktq_pdeq_prev)(struct pktq *pq, int prec, void *prev_p)
655 {
656 	struct pktq_prec *q;
657 	void *p = NULL;
658 
659 	/* protect shared resource */
660 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
661 		return NULL;
662 
663 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
664 
665 	q = &pq->q[prec];
666 
667 	if (prev_p == NULL)
668 		goto done;
669 
670 	if ((p = PKTLINK(prev_p)) == NULL)
671 		goto done;
672 
673 	q->n_pkts--;
674 
675 	pq->n_pkts_tot--;
676 
677 #ifdef WL_TXQ_STALL
678 	q->dequeue_count++;
679 #endif
680 	PKTSETLINK(prev_p, PKTLINK(p));
681 	PKTSETLINK(p, NULL);
682 
683 done:
684 	/* protect shared resource */
685 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
686 		return NULL;
687 
688 	return p;
689 }
690 
691 void *
BCMFASTPATH(pktq_pdeq_with_fn)692 BCMFASTPATH(pktq_pdeq_with_fn)(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg)
693 {
694 	struct pktq_prec *q;
695 	void *p, *prev = NULL;
696 
697 	/* protect shared resource */
698 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
699 		return NULL;
700 
701 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
702 
703 	q = &pq->q[prec];
704 	p = q->head;
705 
706 	while (p) {
707 		if (fn == NULL || (*fn)(p, arg)) {
708 			break;
709 		} else {
710 			prev = p;
711 			p = PKTLINK(p);
712 		}
713 	}
714 	if (p == NULL)
715 		goto done;
716 
717 	if (prev == NULL) {
718 		if ((q->head = PKTLINK(p)) == NULL) {
719 			q->tail = NULL;
720 		}
721 	} else {
722 		PKTSETLINK(prev, PKTLINK(p));
723 		if (q->tail == p) {
724 			q->tail = prev;
725 		}
726 	}
727 
728 	q->n_pkts--;
729 
730 	pq->n_pkts_tot--;
731 
732 #ifdef WL_TXQ_STALL
733 	q->dequeue_count++;
734 #endif
735 	PKTSETLINK(p, NULL);
736 
737 done:
738 	/* protect shared resource */
739 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
740 		return NULL;
741 
742 	return p;
743 }
744 
745 bool
BCMFASTPATH(pktq_pdel)746 BCMFASTPATH(pktq_pdel)(struct pktq *pq, void *pktbuf, int prec)
747 {
748 	bool ret = FALSE;
749 	struct pktq_prec *q;
750 	void *p = NULL;
751 
752 	/* protect shared resource */
753 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
754 		return FALSE;
755 
756 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
757 
758 	/* Should this just assert pktbuf? */
759 	if (!pktbuf)
760 		goto done;
761 
762 	q = &pq->q[prec];
763 
764 	if (q->head == pktbuf) {
765 		if ((q->head = PKTLINK(pktbuf)) == NULL)
766 			q->tail = NULL;
767 	} else {
768 		for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
769 			;
770 		if (p == NULL)
771 			goto done;
772 
773 		PKTSETLINK(p, PKTLINK(pktbuf));
774 		if (q->tail == pktbuf)
775 			q->tail = p;
776 	}
777 
778 	q->n_pkts--;
779 	pq->n_pkts_tot--;
780 
781 #ifdef WL_TXQ_STALL
782 	q->dequeue_count++;
783 #endif
784 
785 	PKTSETLINK(pktbuf, NULL);
786 	ret = TRUE;
787 
788 done:
789 	/* protect shared resource */
790 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
791 		return FALSE;
792 
793 	return ret;
794 }
795 
796 static void
_pktq_pfilter(struct pktq * pq,int prec,pktq_filter_t fltr,void * fltr_ctx,defer_free_pkt_fn_t defer,void * defer_ctx)797 _pktq_pfilter(struct pktq *pq, int prec, pktq_filter_t fltr, void* fltr_ctx,
798               defer_free_pkt_fn_t defer, void *defer_ctx)
799 {
800 	struct pktq_prec wq;
801 	struct pktq_prec *q;
802 	void *p;
803 
804 	/* protect shared resource */
805 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
806 		return;
807 
808 	/* move the prec queue aside to a work queue */
809 	q = &pq->q[prec];
810 
811 	wq = *q;
812 
813 	q->head = NULL;
814 	q->tail = NULL;
815 	q->n_pkts = 0;
816 
817 #ifdef WL_TXQ_STALL
818 	q->dequeue_count += wq.n_pkts;
819 #endif
820 
821 	pq->n_pkts_tot -= wq.n_pkts;
822 
823 	/* protect shared resource */
824 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
825 		return;
826 
827 	/* start with the head of the work queue */
828 	while ((p = wq.head) != NULL) {
829 		/* unlink the current packet from the list */
830 		wq.head = PKTLINK(p);
831 		PKTSETLINK(p, NULL);
832 		wq.n_pkts--;
833 
834 #ifdef WL_TXQ_STALL
835 		wq.dequeue_count++;
836 #endif
837 
838 		/* call the filter function on current packet */
839 		ASSERT(fltr != NULL);
840 		switch ((*fltr)(fltr_ctx, p)) {
841 		case PKT_FILTER_NOACTION:
842 			/* put this packet back */
843 			pktq_penq(pq, prec, p);
844 			break;
845 
846 		case PKT_FILTER_DELETE:
847 			/* delete this packet */
848 			ASSERT(defer != NULL);
849 			(*defer)(defer_ctx, p);
850 			break;
851 
852 		case PKT_FILTER_REMOVE:
853 			/* pkt already removed from list */
854 			break;
855 
856 		default:
857 			ASSERT(0);
858 			break;
859 		}
860 	}
861 
862 	ASSERT(wq.n_pkts == 0);
863 }
864 
865 void
pktq_pfilter(struct pktq * pq,int prec,pktq_filter_t fltr,void * fltr_ctx,defer_free_pkt_fn_t defer,void * defer_ctx,flush_free_pkt_fn_t flush,void * flush_ctx)866 pktq_pfilter(struct pktq *pq, int prec, pktq_filter_t fltr, void* fltr_ctx,
867 	defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx)
868 {
869 	_pktq_pfilter(pq, prec, fltr, fltr_ctx, defer, defer_ctx);
870 
871 	ASSERT(flush != NULL);
872 	(*flush)(flush_ctx);
873 }
874 
875 void
pktq_filter(struct pktq * pq,pktq_filter_t fltr,void * fltr_ctx,defer_free_pkt_fn_t defer,void * defer_ctx,flush_free_pkt_fn_t flush,void * flush_ctx)876 pktq_filter(struct pktq *pq, pktq_filter_t fltr, void* fltr_ctx,
877 	defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx)
878 {
879 	bool filter = FALSE;
880 
881 	/* protect shared resource */
882 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
883 		return;
884 
885 	/* Optimize if pktq n_pkts = 0, just return.
886 	 * pktq len of 0 means pktq's prec q's are all empty.
887 	 */
888 	if (pq->n_pkts_tot > 0) {
889 		filter = TRUE;
890 	}
891 
892 	/* protect shared resource */
893 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
894 		return;
895 
896 	if (filter) {
897 		int prec;
898 
899 		PKTQ_PREC_ITER(pq, prec) {
900 			_pktq_pfilter(pq, prec, fltr, fltr_ctx, defer, defer_ctx);
901 		}
902 
903 		ASSERT(flush != NULL);
904 		(*flush)(flush_ctx);
905 	}
906 }
907 
908 void
spktq_filter(struct spktq * spq,pktq_filter_t fltr,void * fltr_ctx,defer_free_pkt_fn_t defer,void * defer_ctx,flush_free_pkt_fn_t flush,void * flush_ctx)909 spktq_filter(struct spktq *spq, pktq_filter_t fltr, void* fltr_ctx,
910 	defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx)
911 {
912 	struct pktq_prec wq;
913 	struct pktq_prec *q;
914 	void *p = NULL;
915 
916 	/* protect shared resource */
917 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
918 		return;
919 
920 	q = &spq->q;
921 
922 	/* Optimize if pktq_prec n_pkts = 0, just return. */
923 	if (q->n_pkts == 0) {
924 		(void)HND_PKTQ_MUTEX_RELEASE(&spq->mutex);
925 		return;
926 	}
927 
928 	wq = *q;
929 
930 	q->head = NULL;
931 	q->tail = NULL;
932 	q->n_pkts = 0;
933 
934 #ifdef WL_TXQ_STALL
935 	q->dequeue_count += wq.n_pkts;
936 #endif
937 
938 	/* protect shared resource */
939 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
940 		return;
941 
942 	/* start with the head of the work queue */
943 
944 	while ((p = wq.head) != NULL) {
945 		/* unlink the current packet from the list */
946 		wq.head = PKTLINK(p);
947 		PKTSETLINK(p, NULL);
948 		wq.n_pkts--;
949 
950 #ifdef WL_TXQ_STALL
951 		wq.dequeue_count++;
952 #endif
953 
954 		/* call the filter function on current packet */
955 		ASSERT(fltr != NULL);
956 		switch ((*fltr)(fltr_ctx, p)) {
957 		case PKT_FILTER_NOACTION:
958 			/* put this packet back */
959 			spktq_enq(spq, p);
960 			break;
961 
962 		case PKT_FILTER_DELETE:
963 			/* delete this packet */
964 			ASSERT(defer != NULL);
965 			(*defer)(defer_ctx, p);
966 			break;
967 
968 		case PKT_FILTER_REMOVE:
969 			/* pkt already removed from list */
970 			break;
971 
972 		default:
973 			ASSERT(0);
974 			break;
975 		}
976 	}
977 
978 	ASSERT(wq.n_pkts == 0);
979 
980 	ASSERT(flush != NULL);
981 	(*flush)(flush_ctx);
982 }
983 
984 bool
pktq_init(struct pktq * pq,int num_prec,uint max_pkts)985 pktq_init(struct pktq *pq, int num_prec, uint max_pkts)
986 {
987 	int prec;
988 
989 	ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
990 
991 	/* pq is variable size; only zero out what's requested */
992 	bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
993 
994 	if (HND_PKTQ_MUTEX_CREATE("pktq", &pq->mutex) != OSL_EXT_SUCCESS)
995 		return FALSE;
996 
997 	pq->num_prec = (uint16)num_prec;
998 
999 	pq->max_pkts = (uint16)max_pkts;
1000 
1001 	for (prec = 0; prec < num_prec; prec++)
1002 		pq->q[prec].max_pkts = pq->max_pkts;
1003 
1004 	return TRUE;
1005 }
1006 
1007 bool
spktq_init(struct spktq * spq,uint max_pkts)1008 spktq_init(struct spktq *spq, uint max_pkts)
1009 {
1010 	bzero(spq, sizeof(struct spktq));
1011 
1012 	if (HND_PKTQ_MUTEX_CREATE("spktq", &spq->mutex) != OSL_EXT_SUCCESS)
1013 		return FALSE;
1014 
1015 	spq->q.max_pkts = (uint16)max_pkts;
1016 
1017 	return TRUE;
1018 }
1019 
1020 bool
spktq_init_list(struct spktq * spq,uint max_pkts,void * head,void * tail,uint16 n_pkts)1021 spktq_init_list(struct spktq *spq, uint max_pkts, void *head, void *tail, uint16 n_pkts)
1022 {
1023 	if (HND_PKTQ_MUTEX_CREATE("spktq", &spq->mutex) != OSL_EXT_SUCCESS)
1024 		return FALSE;
1025 
1026 	ASSERT(PKTLINK(tail) == NULL);
1027 	PKTSETLINK(tail, NULL);
1028 	spq->q.head = head;
1029 	spq->q.tail = tail;
1030 	spq->q.max_pkts = (uint16)max_pkts;
1031 	spq->q.n_pkts = n_pkts;
1032 	spq->q.stall_count = 0;
1033 	spq->q.dequeue_count = 0;
1034 
1035 	return TRUE;
1036 }
1037 
1038 bool
pktq_deinit(struct pktq * pq)1039 pktq_deinit(struct pktq *pq)
1040 {
1041 	BCM_REFERENCE(pq);
1042 	if (HND_PKTQ_MUTEX_DELETE(&pq->mutex) != OSL_EXT_SUCCESS)
1043 		return FALSE;
1044 
1045 	return TRUE;
1046 }
1047 
1048 bool
spktq_deinit(struct spktq * spq)1049 spktq_deinit(struct spktq *spq)
1050 {
1051 	BCM_REFERENCE(spq);
1052 	if (HND_PKTQ_MUTEX_DELETE(&spq->mutex) != OSL_EXT_SUCCESS)
1053 		return FALSE;
1054 
1055 	return TRUE;
1056 }
1057 
1058 void
pktq_set_max_plen(struct pktq * pq,int prec,uint max_pkts)1059 pktq_set_max_plen(struct pktq *pq, int prec, uint max_pkts)
1060 {
1061 	ASSERT(prec >= 0 && prec < pq->num_prec);
1062 
1063 	/* protect shared resource */
1064 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1065 		return;
1066 
1067 	if (prec < pq->num_prec)
1068 		pq->q[prec].max_pkts = (uint16)max_pkts;
1069 
1070 	/* protect shared resource */
1071 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1072 		return;
1073 }
1074 
1075 void *
BCMFASTPATH(pktq_deq)1076 BCMFASTPATH(pktq_deq)(struct pktq *pq, int *prec_out)
1077 {
1078 	struct pktq_prec *q;
1079 	void *p = NULL;
1080 	int prec;
1081 
1082 	/* protect shared resource */
1083 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1084 		return NULL;
1085 
1086 	if (pq->n_pkts_tot == 0)
1087 		goto done;
1088 
1089 	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1090 		pq->hi_prec--;
1091 
1092 	q = &pq->q[prec];
1093 
1094 	if ((p = q->head) == NULL)
1095 		goto done;
1096 
1097 	if ((q->head = PKTLINK(p)) == NULL)
1098 		q->tail = NULL;
1099 
1100 	q->n_pkts--;
1101 
1102 	pq->n_pkts_tot--;
1103 
1104 #ifdef WL_TXQ_STALL
1105 	q->dequeue_count++;
1106 #endif
1107 
1108 	if (prec_out)
1109 		*prec_out = prec;
1110 
1111 	PKTSETLINK(p, NULL);
1112 
1113 done:
1114 	/* protect shared resource */
1115 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1116 		return NULL;
1117 
1118 	return p;
1119 }
1120 
1121 void *
BCMFASTPATH(pktq_deq_tail)1122 BCMFASTPATH(pktq_deq_tail)(struct pktq *pq, int *prec_out)
1123 {
1124 	struct pktq_prec *q;
1125 	void *p = NULL, *prev;
1126 	int prec;
1127 
1128 	/* protect shared resource */
1129 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1130 		return NULL;
1131 
1132 	if (pq->n_pkts_tot == 0)
1133 		goto done;
1134 
1135 	for (prec = 0; prec < pq->hi_prec; prec++)
1136 		if (pq->q[prec].head)
1137 			break;
1138 
1139 	q = &pq->q[prec];
1140 
1141 	if ((p = q->head) == NULL)
1142 		goto done;
1143 
1144 	for (prev = NULL; p != q->tail; p = PKTLINK(p))
1145 		prev = p;
1146 
1147 	if (prev)
1148 		PKTSETLINK(prev, NULL);
1149 	else
1150 		q->head = NULL;
1151 
1152 	q->tail = prev;
1153 	q->n_pkts--;
1154 
1155 	pq->n_pkts_tot--;
1156 
1157 #ifdef WL_TXQ_STALL
1158 	q->dequeue_count++;
1159 #endif
1160 
1161 	if (prec_out)
1162 		*prec_out = prec;
1163 
1164 	PKTSETLINK(p, NULL);
1165 
1166 done:
1167 	/* protect shared resource */
1168 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1169 		return NULL;
1170 
1171 	return p;
1172 }
1173 
1174 void *
pktq_peek(struct pktq * pq,int * prec_out)1175 pktq_peek(struct pktq *pq, int *prec_out)
1176 {
1177 	int prec;
1178 	void *p = NULL;
1179 
1180 	/* protect shared resource */
1181 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1182 		return NULL;
1183 
1184 	if (pq->n_pkts_tot == 0)
1185 		goto done;
1186 
1187 	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1188 		pq->hi_prec--;
1189 
1190 	if (prec_out)
1191 		*prec_out = prec;
1192 
1193 	p = pq->q[prec].head;
1194 
1195 done:
1196 	/* protect shared resource */
1197 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1198 		return NULL;
1199 
1200 	return p;
1201 }
1202 
1203 void *
spktq_peek(struct spktq * spq)1204 spktq_peek(struct spktq *spq)
1205 {
1206 	void *p = NULL;
1207 
1208 	/* protect shared resource */
1209 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1210 		return NULL;
1211 
1212 	if (spq->q.n_pkts == 0)
1213 		goto done;
1214 
1215 	p = spq->q.head;
1216 
1217 done:
1218 	/* protect shared resource */
1219 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
1220 		return NULL;
1221 
1222 	return p;
1223 }
1224 
1225 void
pktq_pflush(osl_t * osh,struct pktq * pq,int prec,bool dir)1226 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
1227 {
1228 	void *p;
1229 
1230 	/* no need for a mutex protection! */
1231 
1232 	/* start with the head of the list */
1233 	while ((p = pktq_pdeq(pq, prec)) != NULL) {
1234 
1235 		/* delete this packet */
1236 		PKTFREE(osh, p, dir);
1237 	}
1238 }
1239 
1240 void
spktq_flush_ext(osl_t * osh,struct spktq * spq,bool dir,void (* pktq_flush_cb)(void * ctx,void * pkt),void * pktq_flush_ctx)1241 spktq_flush_ext(osl_t *osh, struct spktq *spq, bool dir,
1242 	void (*pktq_flush_cb)(void *ctx, void *pkt), void *pktq_flush_ctx)
1243 {
1244 	void *pkt;
1245 
1246 	/* no need for a mutex protection! */
1247 
1248 	/* start with the head of the list */
1249 	while ((pkt = spktq_deq(spq)) != NULL) {
1250 		if (pktq_flush_cb != NULL) {
1251 			pktq_flush_cb(pktq_flush_ctx, pkt);
1252 		}
1253 		/* delete this packet */
1254 		PKTFREE(osh, pkt, dir);
1255 	}
1256 }
1257 
1258 typedef struct {
1259 	spktq_cb_t cb;
1260 	void *arg;
1261 } spktq_cbinfo_t;
1262 static spktq_cbinfo_t spktq_cbinfo = {NULL, NULL};
1263 static spktq_cbinfo_t *spktq_cbinfo_get(void);
1264 
1265 /* Accessor function forced into RAM to keep spktq_cbinfo out of shdat */
1266 static spktq_cbinfo_t*
BCMRAMFN(spktq_cbinfo_get)1267 BCMRAMFN(spktq_cbinfo_get)(void)
1268 {
1269 	return (&spktq_cbinfo);
1270 }
1271 
1272 void
BCMATTACHFN(spktq_free_register)1273 BCMATTACHFN(spktq_free_register)(spktq_cb_t cb, void *arg)
1274 {
1275 	spktq_cbinfo_t *cbinfop = spktq_cbinfo_get();
1276 	cbinfop->cb = cb;
1277 	cbinfop->arg = arg;
1278 }
1279 
1280 void
spktq_cb(void * spq)1281 spktq_cb(void *spq)
1282 {
1283 	spktq_cbinfo_t *cbinfop = spktq_cbinfo_get();
1284 	if (cbinfop->cb) {
1285 		cbinfop->cb(cbinfop->arg, spq);
1286 	}
1287 }
1288 
1289 void
pktq_flush(osl_t * osh,struct pktq * pq,bool dir)1290 pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
1291 {
1292 	bool flush = FALSE;
1293 
1294 	/* protect shared resource */
1295 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1296 		return;
1297 
1298 	/* Optimize flush, if pktq n_pkts_tot = 0, just return.
1299 	 * pktq len of 0 means pktq's prec q's are all empty.
1300 	 */
1301 	if (pq->n_pkts_tot > 0) {
1302 		flush = TRUE;
1303 	}
1304 
1305 	/* protect shared resource */
1306 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1307 		return;
1308 
1309 	if (flush) {
1310 		int prec;
1311 
1312 		PKTQ_PREC_ITER(pq, prec) {
1313 			pktq_pflush(osh, pq, prec, dir);
1314 		}
1315 	}
1316 }
1317 
1318 /* Return sum of lengths of a specific set of precedences */
1319 int
pktq_mlen(struct pktq * pq,uint prec_bmp)1320 pktq_mlen(struct pktq *pq, uint prec_bmp)
1321 {
1322 	int prec, len;
1323 
1324 	/* protect shared resource */
1325 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1326 		return 0;
1327 
1328 	len = 0;
1329 
1330 	for (prec = 0; prec <= pq->hi_prec; prec++)
1331 		if (prec_bmp & (1 << prec))
1332 			len += pq->q[prec].n_pkts;
1333 
1334 	/* protect shared resource */
1335 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1336 		return 0;
1337 
1338 	return len;
1339 }
1340 
1341 /* Priority peek from a specific set of precedences */
1342 void *
BCMFASTPATH(pktq_mpeek)1343 BCMFASTPATH(pktq_mpeek)(struct pktq *pq, uint prec_bmp, int *prec_out)
1344 {
1345 	struct pktq_prec *q;
1346 	void *p = NULL;
1347 	int prec;
1348 
1349 	/* protect shared resource */
1350 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1351 		return NULL;
1352 
1353 	if (pq->n_pkts_tot == 0)
1354 		goto done;
1355 
1356 	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1357 		pq->hi_prec--;
1358 
1359 	while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
1360 		if (prec-- == 0)
1361 			goto done;
1362 
1363 	q = &pq->q[prec];
1364 
1365 	if ((p = q->head) == NULL)
1366 		goto done;
1367 
1368 	if (prec_out)
1369 		*prec_out = prec;
1370 
1371 done:
1372 	/* protect shared resource */
1373 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1374 		return NULL;
1375 
1376 	return p;
1377 }
1378 /* Priority dequeue from a specific set of precedences */
1379 void *
BCMPOSTTRAPFASTPATH(pktq_mdeq)1380 BCMPOSTTRAPFASTPATH(pktq_mdeq)(struct pktq *pq, uint prec_bmp, int *prec_out)
1381 {
1382 	struct pktq_prec *q;
1383 	void *p = NULL;
1384 	int prec;
1385 
1386 	/* protect shared resource */
1387 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1388 		return NULL;
1389 
1390 	if (pq->n_pkts_tot == 0)
1391 		goto done;
1392 
1393 	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1394 		pq->hi_prec--;
1395 
1396 	while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0))
1397 		if (prec-- == 0)
1398 			goto done;
1399 
1400 	q = &pq->q[prec];
1401 
1402 	if ((p = q->head) == NULL)
1403 		goto done;
1404 
1405 	if ((q->head = PKTLINK(p)) == NULL)
1406 		q->tail = NULL;
1407 
1408 	q->n_pkts--;
1409 
1410 	// terence 20150308: fix for non-null pointer of skb->prev sent from ndo_start_xmit
1411 	if (q->n_pkts == 0) {
1412 		q->head = NULL;
1413 		q->tail = NULL;
1414 	}
1415 
1416 #ifdef WL_TXQ_STALL
1417 	q->dequeue_count++;
1418 #endif
1419 
1420 	if (prec_out)
1421 		*prec_out = prec;
1422 
1423 	pq->n_pkts_tot--;
1424 
1425 	PKTSETLINK(p, NULL);
1426 
1427 done:
1428 	/* protect shared resource */
1429 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1430 		return NULL;
1431 
1432 	return p;
1433 }
1434 
1435 #ifdef HND_PKTQ_THREAD_SAFE
1436 int
pktqprec_avail_pkts(struct pktq * pq,int prec)1437 pktqprec_avail_pkts(struct pktq *pq, int prec)
1438 {
1439 	int ret;
1440 
1441 	/* protect shared resource */
1442 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1443 		return 0;
1444 
1445 	ASSERT(prec >= 0 && prec < pq->num_prec);
1446 
1447 	ret = pq->q[prec].max_pkts - pq->q[prec].n_pkts;
1448 
1449 	/* protect shared resource */
1450 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1451 		return 0;
1452 
1453 	return ret;
1454 }
1455 
1456 bool
BCMFASTPATH(pktqprec_full)1457 BCMFASTPATH(pktqprec_full)(struct pktq *pq, int prec)
1458 {
1459 	bool ret;
1460 
1461 	/* protect shared resource */
1462 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1463 		return FALSE;
1464 
1465 	ASSERT_FP(prec >= 0 && prec < pq->num_prec);
1466 
1467 	ret = pq->q[prec].n_pkts >= pq->q[prec].max_pkts;
1468 
1469 	/* protect shared resource */
1470 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1471 		return FALSE;
1472 
1473 	return ret;
1474 }
1475 
1476 int
pktq_avail(struct pktq * pq)1477 pktq_avail(struct pktq *pq)
1478 {
1479 	int ret;
1480 
1481 	/* protect shared resource */
1482 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1483 		return 0;
1484 
1485 	ret = pq->max_pkts - pq->n_pkts_tot;
1486 
1487 	/* protect shared resource */
1488 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1489 		return 0;
1490 
1491 	return ret;
1492 }
1493 
1494 int
spktq_avail(struct spktq * spq)1495 spktq_avail(struct spktq *spq)
1496 {
1497 	int ret;
1498 
1499 	/* protect shared resource */
1500 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1501 		return 0;
1502 
1503 	ret = spq->q.max_pkts - spq->q.n_pkts;
1504 
1505 	/* protect shared resource */
1506 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
1507 		return 0;
1508 
1509 	return ret;
1510 }
1511 
1512 bool
pktq_full(struct pktq * pq)1513 pktq_full(struct pktq *pq)
1514 {
1515 	bool ret;
1516 
1517 	/* protect shared resource */
1518 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1519 		return FALSE;
1520 
1521 	ret = pq->n_pkts_tot >= pq->max_pkts;
1522 
1523 	/* protect shared resource */
1524 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
1525 		return FALSE;
1526 
1527 	return ret;
1528 }
1529 
1530 bool
spktq_full(struct spktq * spq)1531 spktq_full(struct spktq *spq)
1532 {
1533 	bool ret;
1534 
1535 	/* protect shared resource */
1536 	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
1537 		return FALSE;
1538 
1539 	ret = spq->q.n_pkts >= spq->q.max_pkts;
1540 
1541 	/* protect shared resource */
1542 	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
1543 		return FALSE;
1544 
1545 	return ret;
1546 }
1547 
1548 #endif	/* HND_PKTQ_THREAD_SAFE */
1549