From cde9070d9970eef1f7ec2360586c802a16230ad8 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 10 May 2024 07:43:50 +0000
Subject: [PATCH] rtl88x2CE_WiFi_linux driver

---
 kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hnd_pktq.c | 1029 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 782 insertions(+), 247 deletions(-)

diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hnd_pktq.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hnd_pktq.c
index bbf3189..c305cce 100644
--- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hnd_pktq.c
+++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hnd_pktq.c
@@ -1,15 +1,16 @@
-/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * HND generic pktq operation primitives
  *
- * Copyright (C) 1999-2019, Broadcom Corporation
- * 
+ * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation
+ *
+ * Copyright (C) 1999-2017, Broadcom Corporation
+ *
  *      Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
  * under the terms of the GNU General Public License version 2 (the "GPL"),
  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  * following added to such license:
- * 
+ *
  *      As a special exception, the copyright holders of this software give you
  * permission to link this software with independent modules, and to copy and
  * distribute the resulting executable under terms of your choice, provided that
@@ -17,7 +18,7 @@
  * the license of that module.  An independent module is a module which is not
  * derived from this software.  The special exception does not apply to any
  * modifications of the software.
- * 
+ *
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
@@ -25,7 +26,7 @@
  *
  * <<Broadcom-WL-IPTag/Open:>>
  *
- * $Id: $
+ * $Id: hnd_pktq.c 698847 2017-05-11 00:10:48Z $
  */
 
 #include <typedefs.h>
@@ -45,8 +46,13 @@
 #define HND_PKTQ_MUTEX_DELETE(mutex)		OSL_EXT_SUCCESS
 #define HND_PKTQ_MUTEX_ACQUIRE(mutex, msec)	OSL_EXT_SUCCESS
 #define HND_PKTQ_MUTEX_RELEASE(mutex)		OSL_EXT_SUCCESS
-#endif
+#endif /* HND_PKTQ_THREAD_SAFE */
 
+/* status during txfifo sync */
+#if defined(WLAMPDU_MAC) && defined(PROP_TXSTATUS)
+#define TXQ_PKT_DEL		0x01
+#define HEAD_PKT_FLUSHED	0xFF
+#endif /* defined(WLAMPDU_MAC) && defined(PROP_TXSTATUS) */
 /*
  * osl multiple-precedence packet queue
  * hi_prec is always >= the number of the highest non-empty precedence
@@ -61,12 +67,10 @@
 		return NULL;
 
 	ASSERT(prec >= 0 && prec < pq->num_prec);
-	/* queueing chains not allowed and no segmented SKB (Kernel-3.18.y) */
-	//ASSERT(!((PKTLINK(p) != NULL) && (PKTLINK(p) != p)));
+	ASSERT(PKTLINK(p) == NULL);		/* queueing chains not allowed */
 
 	ASSERT(!pktq_full(pq));
-	ASSERT(!pktq_pfull(pq, prec));
-	PKTSETLINK(p, NULL);
+	ASSERT(!pktqprec_full(pq, prec));
 
 	q = &pq->q[prec];
 
@@ -76,15 +80,48 @@
 		q->head = p;
 
 	q->tail = p;
-	q->len++;
+	q->n_pkts++;
 
-	pq->len++;
+	pq->n_pkts_tot++;
 
 	if (pq->hi_prec < prec)
 		pq->hi_prec = (uint8)prec;
 
 	/* protect shared resource */
 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	return p;
+}
+
+/*
+ * osl simple, non-priority packet queue
+ */
+void * BCMFASTPATH
+spktq_enq(struct spktq *spq, void *p)
+{
+	struct pktq_prec *q;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	ASSERT(!spktq_full(spq));
+
+	PKTSETLINK(p, NULL);
+
+	q = &spq->q;
+
+	if (q->head)
+		PKTSETLINK(q->tail, p);
+	else
+		q->head = p;
+
+	q->tail = p;
+	q->n_pkts++;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
 		return NULL;
 
 	return p;
@@ -100,12 +137,10 @@
 		return NULL;
 
 	ASSERT(prec >= 0 && prec < pq->num_prec);
-	/* queueing chains not allowed and no segmented SKB (Kernel-3.18.y) */
-	//ASSERT(!((PKTLINK(p) != NULL) && (PKTLINK(p) != p)));
+	ASSERT(PKTLINK(p) == NULL);		/* queueing chains not allowed */
 
 	ASSERT(!pktq_full(pq));
-	ASSERT(!pktq_pfull(pq, prec));
-	PKTSETLINK(p, NULL);
+	ASSERT(!pktqprec_full(pq, prec));
 
 	q = &pq->q[prec];
 
@@ -114,9 +149,9 @@
 
 	PKTSETLINK(p, q->head);
 	q->head = p;
-	q->len++;
+	q->n_pkts++;
 
-	pq->len++;
+	pq->n_pkts_tot++;
 
 	if (pq->hi_prec < prec)
 		pq->hi_prec = (uint8)prec;
@@ -128,110 +163,33 @@
 	return p;
 }
 
-/*
- * Append spktq 'list' to the tail of pktq 'pq'
- */
-void BCMFASTPATH
-pktq_append(struct pktq *pq, int prec, struct spktq *list)
+void * BCMFASTPATH
+spktq_enq_head(struct spktq *spq, void *p)
 {
 	struct pktq_prec *q;
-	struct pktq_prec *list_q;
 
 	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
-		return;
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return NULL;
 
-	list_q = &list->q[0];
+	ASSERT(!spktq_full(spq));
 
-	/* empty list check */
-	if (list_q->head == NULL)
-		goto done;
+	PKTSETLINK(p, NULL);
 
-	ASSERT(prec >= 0 && prec < pq->num_prec);
-	ASSERT(PKTLINK(list_q->tail) == NULL);         /* terminated list */
+	q = &spq->q;
 
-	ASSERT(!pktq_full(pq));
-	ASSERT(!pktq_pfull(pq, prec));
+	if (q->head == NULL)
+		q->tail = p;
 
-	q = &pq->q[prec];
-
-	if (q->head)
-		PKTSETLINK(q->tail, list_q->head);
-	else
-		q->head = list_q->head;
-
-	q->tail = list_q->tail;
-	q->len += list_q->len;
-	pq->len += list_q->len;
-
-	if (pq->hi_prec < prec)
-		pq->hi_prec = (uint8)prec;
-
-	list_q->head = NULL;
-	list_q->tail = NULL;
-	list_q->len = 0;
-	list->len = 0;
-
-done:
-	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
-		return;
-}
-
-/*
- * Prepend spktq 'list' to the head of pktq 'pq'
- */
-void BCMFASTPATH
-pktq_prepend(struct pktq *pq, int prec, struct spktq *list)
-{
-	struct pktq_prec *q;
-	struct pktq_prec *list_q;
+	PKTSETLINK(p, q->head);
+	q->head = p;
+	q->n_pkts++;
 
 	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
-		return;
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
+		return NULL;
 
-	list_q = &list->q[0];
-
-	/* empty list check */
-	if (list_q->head == NULL)
-		goto done;
-
-	ASSERT(prec >= 0 && prec < pq->num_prec);
-	ASSERT(PKTLINK(list_q->tail) == NULL);         /* terminated list */
-
-	ASSERT(!pktq_full(pq));
-	ASSERT(!pktq_pfull(pq, prec));
-
-	q = &pq->q[prec];
-
-	/* set the tail packet of list to point at the former pq head */
-	PKTSETLINK(list_q->tail, q->head);
-	/* the new q head is the head of list */
-	q->head = list_q->head;
-
-	/* If the q tail was non-null, then it stays as is.
-	 * If the q tail was null, it is now the tail of list
-	 */
-	if (q->tail == NULL) {
-		q->tail = list_q->tail;
-	}
-
-	q->len += list_q->len;
-	pq->len += list_q->len;
-
-	if (pq->hi_prec < prec)
-		pq->hi_prec = (uint8)prec;
-
-	list_q->head = NULL;
-	list_q->tail = NULL;
-	list_q->len = 0;
-	list->len = 0;
-
-done:
-	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
-		return;
+	return p;
 }
 
 void * BCMFASTPATH
@@ -254,9 +212,13 @@
 	if ((q->head = PKTLINK(p)) == NULL)
 		q->tail = NULL;
 
-	q->len--;
+	q->n_pkts--;
 
-	pq->len--;
+	pq->n_pkts_tot--;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
 
 	PKTSETLINK(p, NULL);
 
@@ -266,6 +228,360 @@
 		return NULL;
 
 	return p;
+}
+
+void * BCMFASTPATH
+spktq_deq(struct spktq *spq)
+{
+	struct pktq_prec *q;
+	void *p;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	q = &spq->q;
+
+	if ((p = q->head) == NULL)
+		goto done;
+
+	if ((q->head = PKTLINK(p)) == NULL)
+		q->tail = NULL;
+
+	q->n_pkts--;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
+
+	PKTSETLINK(p, NULL);
+
+done:
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	return p;
+}
+
+void * BCMFASTPATH
+pktq_pdeq_tail(struct pktq *pq, int prec)
+{
+	struct pktq_prec *q;
+	void *p, *prev;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	ASSERT(prec >= 0 && prec < pq->num_prec);
+
+	q = &pq->q[prec];
+
+	if ((p = q->head) == NULL)
+		goto done;
+
+	for (prev = NULL; p != q->tail; p = PKTLINK(p))
+		prev = p;
+
+	if (prev)
+		PKTSETLINK(prev, NULL);
+	else
+		q->head = NULL;
+
+	q->tail = prev;
+	q->n_pkts--;
+
+	pq->n_pkts_tot--;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
+done:
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	return p;
+}
+
+void * BCMFASTPATH
+spktq_deq_tail(struct spktq *spq)
+{
+	struct pktq_prec *q;
+	void *p, *prev;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	q = &spq->q;
+
+	if ((p = q->head) == NULL)
+		goto done;
+
+	for (prev = NULL; p != q->tail; p = PKTLINK(p))
+		prev = p;
+
+	if (prev)
+		PKTSETLINK(prev, NULL);
+	else
+		q->head = NULL;
+
+	q->tail = prev;
+	q->n_pkts--;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
+done:
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	return p;
+}
+
+void *
+pktq_peek_tail(struct pktq *pq, int *prec_out)
+{
+	int prec;
+	void *p = NULL;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	if (pq->n_pkts_tot == 0)
+		goto done;
+
+	for (prec = 0; prec < pq->hi_prec; prec++)
+		if (pq->q[prec].head)
+			break;
+
+	if (prec_out)
+		*prec_out = prec;
+
+	p = pq->q[prec].tail;
+
+done:
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+		return NULL;
+
+	return p;
+}
+
+/*
+ * Append spktq 'list' to the tail of pktq 'pq'
+ */
+void BCMFASTPATH
+pktq_append(struct pktq *pq, int prec, struct spktq *list)
+{
+	struct pktq_prec *q;
+	struct pktq_prec *list_q;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return;
+
+	list_q = &list->q;
+
+	/* empty list check */
+	if (list_q->head == NULL)
+		goto done;
+
+	ASSERT(prec >= 0 && prec < pq->num_prec);
+	ASSERT(PKTLINK(list_q->tail) == NULL);         /* terminated list */
+
+	ASSERT(!pktq_full(pq));
+	ASSERT(!pktqprec_full(pq, prec));
+
+	q = &pq->q[prec];
+
+	if (q->head)
+		PKTSETLINK(q->tail, list_q->head);
+	else
+		q->head = list_q->head;
+
+	q->tail = list_q->tail;
+	q->n_pkts += list_q->n_pkts;
+	pq->n_pkts_tot += list_q->n_pkts;
+
+	if (pq->hi_prec < prec)
+		pq->hi_prec = (uint8)prec;
+
+#ifdef WL_TXQ_STALL
+	list_q->dequeue_count += list_q->n_pkts;
+#endif // endif
+
+	list_q->head = NULL;
+	list_q->tail = NULL;
+	list_q->n_pkts = 0;
+
+done:
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+		return;
+}
+
+/*
+ * Append spktq 'list' to the tail of spktq 'spq'
+ */
+void BCMFASTPATH
+spktq_append(struct spktq *spq, struct spktq *list)
+{
+	struct pktq_prec *q;
+	struct pktq_prec *list_q;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return;
+
+	list_q = &list->q;
+
+	/* empty list check */
+	if (list_q->head == NULL)
+		goto done;
+
+	ASSERT(PKTLINK(list_q->tail) == NULL);         /* terminated list */
+
+	ASSERT(!spktq_full(spq));
+
+	q = &spq->q;
+
+	if (q->head)
+		PKTSETLINK(q->tail, list_q->head);
+	else
+		q->head = list_q->head;
+
+	q->tail = list_q->tail;
+	q->n_pkts += list_q->n_pkts;
+
+#ifdef WL_TXQ_STALL
+	list_q->dequeue_count += list_q->n_pkts;
+#endif // endif
+
+	list_q->head = NULL;
+	list_q->tail = NULL;
+	list_q->n_pkts = 0;
+
+done:
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
+		return;
+}
+
+/*
+ * Prepend spktq 'list' to the head of pktq 'pq'
+ */
+void BCMFASTPATH
+pktq_prepend(struct pktq *pq, int prec, struct spktq *list)
+{
+	struct pktq_prec *q;
+	struct pktq_prec *list_q;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return;
+
+	list_q = &list->q;
+
+	/* empty list check */
+	if (list_q->head == NULL)
+		goto done;
+
+	ASSERT(prec >= 0 && prec < pq->num_prec);
+	ASSERT(PKTLINK(list_q->tail) == NULL);         /* terminated list */
+
+	ASSERT(!pktq_full(pq));
+	ASSERT(!pktqprec_full(pq, prec));
+
+	q = &pq->q[prec];
+
+	/* set the tail packet of list to point at the former pq head */
+	PKTSETLINK(list_q->tail, q->head);
+	/* the new q head is the head of list */
+	q->head = list_q->head;
+
+	/* If the q tail was non-null, then it stays as is.
+	 * If the q tail was null, it is now the tail of list
+	 */
+	if (q->tail == NULL) {
+		q->tail = list_q->tail;
+	}
+
+	q->n_pkts += list_q->n_pkts;
+	pq->n_pkts_tot += list_q->n_pkts;
+
+	if (pq->hi_prec < prec)
+		pq->hi_prec = (uint8)prec;
+
+#ifdef WL_TXQ_STALL
+	list_q->dequeue_count += list_q->n_pkts;
+#endif // endif
+
+	list_q->head = NULL;
+	list_q->tail = NULL;
+	list_q->n_pkts = 0;
+
+done:
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+		return;
+}
+
+/*
+ * Prepend spktq 'list' to the head of spktq 'spq'
+ */
+void BCMFASTPATH
+spktq_prepend(struct spktq *spq, struct spktq *list)
+{
+	struct pktq_prec *q;
+	struct pktq_prec *list_q;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return;
+
+	list_q = &list->q;
+
+	/* empty list check */
+	if (list_q->head == NULL)
+		goto done;
+
+	ASSERT(PKTLINK(list_q->tail) == NULL);         /* terminated list */
+
+	ASSERT(!spktq_full(spq));
+
+	q = &spq->q;
+
+	/* set the tail packet of list to point at the former pq head */
+	PKTSETLINK(list_q->tail, q->head);
+	/* the new q head is the head of list */
+	q->head = list_q->head;
+
+	/* If the q tail was non-null, then it stays as is.
+	 * If the q tail was null, it is now the tail of list
+	 */
+	if (q->tail == NULL) {
+		q->tail = list_q->tail;
+	}
+
+	q->n_pkts += list_q->n_pkts;
+
+#ifdef WL_TXQ_STALL
+	list_q->dequeue_count += list_q->n_pkts;
+#endif // endif
+
+	list_q->head = NULL;
+	list_q->tail = NULL;
+	list_q->n_pkts = 0;
+
+done:
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
+		return;
 }
 
 void * BCMFASTPATH
@@ -288,10 +604,13 @@
 	if ((p = PKTLINK(prev_p)) == NULL)
 		goto done;
 
-	q->len--;
+	q->n_pkts--;
 
-	pq->len--;
+	pq->n_pkts_tot--;
 
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
 	PKTSETLINK(prev_p, PKTLINK(p));
 	PKTSETLINK(p, NULL);
 
@@ -340,10 +659,13 @@
 		}
 	}
 
-	q->len--;
+	q->n_pkts--;
 
-	pq->len--;
+	pq->n_pkts_tot--;
 
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
 	PKTSETLINK(p, NULL);
 
 done:
@@ -352,84 +674,6 @@
 		return NULL;
 
 	return p;
-}
-
-void * BCMFASTPATH
-pktq_pdeq_tail(struct pktq *pq, int prec)
-{
-	struct pktq_prec *q;
-	void *p, *prev;
-
-	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
-		return NULL;
-
-	ASSERT(prec >= 0 && prec < pq->num_prec);
-
-	q = &pq->q[prec];
-
-	if ((p = q->head) == NULL)
-		goto done;
-
-	for (prev = NULL; p != q->tail; p = PKTLINK(p))
-		prev = p;
-
-	if (prev)
-		PKTSETLINK(prev, NULL);
-	else
-		q->head = NULL;
-
-	q->tail = prev;
-	q->len--;
-
-	pq->len--;
-
-done:
-	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
-		return NULL;
-
-	return p;
-}
-
-void
-pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
-{
-	struct pktq_prec *q;
-	void *p, *prev = NULL;
-
-	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
-		return;
-
-	q = &pq->q[prec];
-	p = q->head;
-	while (p) {
-		if (fn == NULL || (*fn)(p, arg)) {
-			bool head = (p == q->head);
-			if (head)
-				q->head = PKTLINK(p);
-			else
-				PKTSETLINK(prev, PKTLINK(p));
-			PKTSETLINK(p, NULL);
-			PKTFREE(osh, p, dir);
-			q->len--;
-			pq->len--;
-			p = (head ? q->head : PKTLINK(prev));
-		} else {
-			prev = p;
-			p = PKTLINK(p);
-		}
-	}
-
-	if (q->head == NULL) {
-		ASSERT(q->len == 0);
-		q->tail = NULL;
-	}
-
-	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
-		return;
 }
 
 bool BCMFASTPATH
@@ -465,8 +709,13 @@
 			q->tail = p;
 	}
 
-	q->len--;
-	pq->len--;
+	q->n_pkts--;
+	pq->n_pkts_tot--;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
+
 	PKTSETLINK(pktbuf, NULL);
 	ret = TRUE;
 
@@ -478,25 +727,226 @@
 	return ret;
 }
 
+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)
+{
+	struct pktq_prec wq;
+	struct pktq_prec *q;
+	void *p;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return;
+
+	/* move the prec queue aside to a work queue */
+	q = &pq->q[prec];
+
+	wq = *q;
+
+	q->head = NULL;
+	q->tail = NULL;
+	q->n_pkts = 0;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count += wq.n_pkts;
+#endif // endif
+
+	pq->n_pkts_tot -= wq.n_pkts;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+		return;
+
+	/* start with the head of the work queue */
+	while ((p = wq.head) != NULL) {
+		/* unlink the current packet from the list */
+		wq.head = PKTLINK(p);
+		PKTSETLINK(p, NULL);
+		wq.n_pkts--;
+
+#ifdef WL_TXQ_STALL
+		wq.dequeue_count++;
+#endif // endif
+
+		/* call the filter function on current packet */
+		ASSERT(fltr != NULL);
+		switch ((*fltr)(fltr_ctx, p)) {
+		case PKT_FILTER_NOACTION:
+			/* put this packet back */
+			pktq_penq(pq, prec, p);
+			break;
+
+		case PKT_FILTER_DELETE:
+			/* delete this packet */
+			ASSERT(defer != NULL);
+			(*defer)(defer_ctx, p);
+			break;
+
+		case PKT_FILTER_REMOVE:
+			/* pkt already removed from list */
+			break;
+
+		default:
+			ASSERT(0);
+			break;
+		}
+	}
+
+	ASSERT(wq.n_pkts == 0);
+}
+
+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)
+{
+	_pktq_pfilter(pq, prec, fltr, fltr_ctx, defer, defer_ctx);
+
+	ASSERT(flush != NULL);
+	(*flush)(flush_ctx);
+}
+
+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)
+{
+	bool filter = FALSE;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return;
+
+	/* Optimize if pktq n_pkts = 0, just return.
+	 * pktq len of 0 means pktq's prec q's are all empty.
+	 */
+	if (pq->n_pkts_tot > 0) {
+		filter = TRUE;
+	}
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+		return;
+
+	if (filter) {
+		int prec;
+
+		PKTQ_PREC_ITER(pq, prec) {
+			_pktq_pfilter(pq, prec, fltr, fltr_ctx, defer, defer_ctx);
+		}
+
+		ASSERT(flush != NULL);
+		(*flush)(flush_ctx);
+	}
+}
+
+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)
+{
+	struct pktq_prec wq;
+	struct pktq_prec *q;
+	void *p = NULL;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return;
+
+	q = &spq->q;
+
+	/* Optimize if pktq_prec n_pkts = 0, just return. */
+	if (q->n_pkts == 0) {
+		(void)HND_PKTQ_MUTEX_RELEASE(&spq->mutex);
+		return;
+	}
+
+	wq = *q;
+
+	q->head = NULL;
+	q->tail = NULL;
+	q->n_pkts = 0;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count += wq.n_pkts;
+#endif // endif
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
+		return;
+
+	/* start with the head of the work queue */
+
+	while ((p = wq.head) != NULL) {
+		/* unlink the current packet from the list */
+		wq.head = PKTLINK(p);
+		PKTSETLINK(p, NULL);
+		wq.n_pkts--;
+
+#ifdef WL_TXQ_STALL
+		wq.dequeue_count++;
+#endif // endif
+
+		/* call the filter function on current packet */
+		ASSERT(fltr != NULL);
+		switch ((*fltr)(fltr_ctx, p)) {
+		case PKT_FILTER_NOACTION:
+			/* put this packet back */
+			spktq_enq(spq, p);
+			break;
+
+		case PKT_FILTER_DELETE:
+			/* delete this packet */
+			ASSERT(defer != NULL);
+			(*defer)(defer_ctx, p);
+			break;
+
+		case PKT_FILTER_REMOVE:
+			/* pkt already removed from list */
+			break;
+
+		default:
+			ASSERT(0);
+			break;
+		}
+	}
+
+	ASSERT(wq.n_pkts == 0);
+
+	ASSERT(flush != NULL);
+	(*flush)(flush_ctx);
+}
+
 bool
-pktq_init(struct pktq *pq, int num_prec, int max_len)
+pktq_init(struct pktq *pq, int num_prec, int max_pkts)
 {
 	int prec;
-
-	if (HND_PKTQ_MUTEX_CREATE("pktq", &pq->mutex) != OSL_EXT_SUCCESS)
-		return FALSE;
 
 	ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
 
 	/* pq is variable size; only zero out what's requested */
 	bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
 
+	if (HND_PKTQ_MUTEX_CREATE("pktq", &pq->mutex) != OSL_EXT_SUCCESS)
+		return FALSE;
+
 	pq->num_prec = (uint16)num_prec;
 
-	pq->max = (uint16)max_len;
+	pq->max_pkts = (uint16)max_pkts;
 
 	for (prec = 0; prec < num_prec; prec++)
-		pq->q[prec].max = pq->max;
+		pq->q[prec].max_pkts = pq->max_pkts;
+
+	return TRUE;
+}
+
+bool
+spktq_init(struct spktq *spq, int max_pkts)
+{
+	bzero(spq, sizeof(struct spktq));
+
+	if (HND_PKTQ_MUTEX_CREATE("spktq", &spq->mutex) != OSL_EXT_SUCCESS)
+		return FALSE;
+
+	spq->q.max_pkts = (uint16)max_pkts;
 
 	return TRUE;
 }
@@ -504,14 +954,25 @@
 bool
 pktq_deinit(struct pktq *pq)
 {
+	BCM_REFERENCE(pq);
 	if (HND_PKTQ_MUTEX_DELETE(&pq->mutex) != OSL_EXT_SUCCESS)
 		return FALSE;
 
 	return TRUE;
 }
 
+bool
+spktq_deinit(struct spktq *spq)
+{
+	BCM_REFERENCE(spq);
+	if (HND_PKTQ_MUTEX_DELETE(&spq->mutex) != OSL_EXT_SUCCESS)
+		return FALSE;
+
+	return TRUE;
+}
+
 void
-pktq_set_max_plen(struct pktq *pq, int prec, int max_len)
+pktq_set_max_plen(struct pktq *pq, int prec, int max_pkts)
 {
 	ASSERT(prec >= 0 && prec < pq->num_prec);
 
@@ -520,7 +981,7 @@
 		return;
 
 	if (prec < pq->num_prec)
-		pq->q[prec].max = (uint16)max_len;
+		pq->q[prec].max_pkts = (uint16)max_pkts;
 
 	/* protect shared resource */
 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
@@ -538,7 +999,7 @@
 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
 		return NULL;
 
-	if (pq->len == 0)
+	if (pq->n_pkts_tot == 0)
 		goto done;
 
 	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
@@ -552,9 +1013,13 @@
 	if ((q->head = PKTLINK(p)) == NULL)
 		q->tail = NULL;
 
-	q->len--;
+	q->n_pkts--;
 
-	pq->len--;
+	pq->n_pkts_tot--;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
 
 	if (prec_out)
 		*prec_out = prec;
@@ -580,7 +1045,7 @@
 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
 		return NULL;
 
-	if (pq->len == 0)
+	if (pq->n_pkts_tot == 0)
 		goto done;
 
 	for (prec = 0; prec < pq->hi_prec; prec++)
@@ -601,9 +1066,13 @@
 		q->head = NULL;
 
 	q->tail = prev;
-	q->len--;
+	q->n_pkts--;
 
-	pq->len--;
+	pq->n_pkts_tot--;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
 
 	if (prec_out)
 		*prec_out = prec;
@@ -628,7 +1097,7 @@
 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
 		return NULL;
 
-	if (pq->len == 0)
+	if (pq->n_pkts_tot == 0)
 		goto done;
 
 	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
@@ -648,59 +1117,84 @@
 }
 
 void *
-pktq_peek_tail(struct pktq *pq, int *prec_out)
+spktq_peek(struct spktq *spq)
 {
-	int prec;
 	void *p = NULL;
 
 	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
 		return NULL;
 
-	if (pq->len == 0)
+	if (spq->q.n_pkts == 0)
 		goto done;
 
-	for (prec = 0; prec < pq->hi_prec; prec++)
-		if (pq->q[prec].head)
-			break;
-
-	if (prec_out)
-		*prec_out = prec;
-
-	p = pq->q[prec].tail;
+	p = spq->q.head;
 
 done:
 	/* protect shared resource */
-	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
 		return NULL;
 
 	return p;
 }
 
 void
-pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
+pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
 {
-	int prec;
+	void *p;
+
+	/* no need for a mutex protection! */
+
+	/* start with the head of the list */
+	while ((p = pktq_pdeq(pq, prec)) != NULL) {
+
+		/* delete this packet */
+		PKTFREE(osh, p, dir);
+	}
+}
+
+void
+spktq_flush(osl_t *osh, struct spktq *spq, bool dir)
+{
+	void *p;
+
+	/* no need for a mutex protection! */
+
+	/* start with the head of the list */
+	while ((p = spktq_deq(spq)) != NULL) {
+
+		/* delete this packet */
+		PKTFREE(osh, p, dir);
+	}
+}
+
+void
+pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
+{
+	bool flush = FALSE;
 
 	/* protect shared resource */
 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
 		return;
 
-	/* Optimize flush, if pktq len = 0, just return.
+	/* Optimize flush, if pktq n_pkts_tot = 0, just return.
 	 * pktq len of 0 means pktq's prec q's are all empty.
 	 */
-	if (pq->len == 0)
-		goto done;
+	if (pq->n_pkts_tot > 0) {
+		flush = TRUE;
+	}
 
-	for (prec = 0; prec < pq->num_prec; prec++)
-		pktq_pflush(osh, pq, prec, dir, fn, arg);
-	if (fn == NULL)
-		ASSERT(pq->len == 0);
-
-done:
 	/* protect shared resource */
 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
 		return;
+
+	if (flush) {
+		int prec;
+
+		PKTQ_PREC_ITER(pq, prec) {
+			pktq_pflush(osh, pq, prec, dir);
+		}
+	}
 }
 
 /* Return sum of lengths of a specific set of precedences */
@@ -717,7 +1211,7 @@
 
 	for (prec = 0; prec <= pq->hi_prec; prec++)
 		if (prec_bmp & (1 << prec))
-			len += pq->q[prec].len;
+			len += pq->q[prec].n_pkts;
 
 	/* protect shared resource */
 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
@@ -738,7 +1232,7 @@
 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
 		return NULL;
 
-	if (pq->len == 0)
+	if (pq->n_pkts_tot == 0)
 		goto done;
 
 	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
@@ -775,7 +1269,7 @@
 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
 		return NULL;
 
-	if (pq->len == 0)
+	if (pq->n_pkts_tot == 0)
 		goto done;
 
 	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
@@ -793,12 +1287,16 @@
 	if ((q->head = PKTLINK(p)) == NULL)
 		q->tail = NULL;
 
-	q->len--;
+	q->n_pkts--;
+
+#ifdef WL_TXQ_STALL
+	q->dequeue_count++;
+#endif // endif
 
 	if (prec_out)
 		*prec_out = prec;
 
-	pq->len--;
+	pq->n_pkts_tot--;
 
 	PKTSETLINK(p, NULL);
 
@@ -812,7 +1310,7 @@
 
 #ifdef HND_PKTQ_THREAD_SAFE
 int
-pktq_pavail(struct pktq *pq, int prec)
+pktqprec_avail_pkts(struct pktq *pq, int prec)
 {
 	int ret;
 
@@ -822,7 +1320,7 @@
 
 	ASSERT(prec >= 0 && prec < pq->num_prec);
 
-	ret = pq->q[prec].max - pq->q[prec].len;
+	ret = pq->q[prec].max_pkts - pq->q[prec].n_pkts;
 
 	/* protect shared resource */
 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
@@ -832,7 +1330,7 @@
 }
 
 bool
-pktq_pfull(struct pktq *pq, int prec)
+pktqprec_full(struct pktq *pq, int prec)
 {
 	bool ret;
 
@@ -842,7 +1340,7 @@
 
 	ASSERT(prec >= 0 && prec < pq->num_prec);
 
-	ret = pq->q[prec].len >= pq->q[prec].max;
+	ret = pq->q[prec].n_pkts >= pq->q[prec].max_pkts;
 
 	/* protect shared resource */
 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
@@ -860,10 +1358,28 @@
 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
 		return 0;
 
-	ret = pq->max - pq->len;
+	ret = pq->max_pkts - pq->n_pkts_tot;
 
 	/* protect shared resource */
 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+		return 0;
+
+	return ret;
+}
+
+int
+spktq_avail(struct spktq *spq)
+{
+	int ret;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return 0;
+
+	ret = spq->q.max_pkts - spq->q.n_pkts;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
 		return 0;
 
 	return ret;
@@ -878,7 +1394,7 @@
 	if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
 		return FALSE;
 
-	ret = pq->len >= pq->max;
+	ret = pq->n_pkts_tot >= pq->max_pkts;
 
 	/* protect shared resource */
 	if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
@@ -886,4 +1402,23 @@
 
 	return ret;
 }
+
+bool
+spktq_full(struct spktq *spq)
+{
+	bool ret;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+		return FALSE;
+
+	ret = spq->q.n_pkts >= spq->q.max_pkts;
+
+	/* protect shared resource */
+	if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS)
+		return FALSE;
+
+	return ret;
+}
+
 #endif	/* HND_PKTQ_THREAD_SAFE */

--
Gitblit v1.6.2