889 lines
17 KiB
C
889 lines
17 KiB
C
|
/*
|
||
|
* HND generic pktq operation primitives
|
||
|
*
|
||
|
* Portions of this code are copyright (c) 2017 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
|
||
|
* you also meet, for each linked independent module, the terms and conditions of
|
||
|
* 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.
|
||
|
*
|
||
|
*
|
||
|
* <<Broadcom-WL-IPTag/Open:>>
|
||
|
*
|
||
|
* $Id: hnd_pktq.c 657686 2016-09-02 06:39:10Z $
|
||
|
*/
|
||
|
|
||
|
#include <typedefs.h>
|
||
|
#include <osl.h>
|
||
|
#include <osl_ext.h>
|
||
|
#include <bcmutils.h>
|
||
|
#include <hnd_pktq.h>
|
||
|
|
||
|
/* mutex macros for thread safe */
|
||
|
#ifdef HND_PKTQ_THREAD_SAFE
|
||
|
#define HND_PKTQ_MUTEX_CREATE(name, mutex) osl_ext_mutex_create(name, mutex)
|
||
|
#define HND_PKTQ_MUTEX_DELETE(mutex) osl_ext_mutex_delete(mutex)
|
||
|
#define HND_PKTQ_MUTEX_ACQUIRE(mutex, msec) osl_ext_mutex_acquire(mutex, msec)
|
||
|
#define HND_PKTQ_MUTEX_RELEASE(mutex) osl_ext_mutex_release(mutex)
|
||
|
#else
|
||
|
#define HND_PKTQ_MUTEX_CREATE(name, mutex) OSL_EXT_SUCCESS
|
||
|
#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
|
||
|
|
||
|
/*
|
||
|
* osl multiple-precedence packet queue
|
||
|
* hi_prec is always >= the number of the highest non-empty precedence
|
||
|
*/
|
||
|
void * BCMFASTPATH
|
||
|
pktq_penq(struct pktq *pq, int prec, void *p)
|
||
|
{
|
||
|
struct pktq_prec *q;
|
||
|
|
||
|
/* 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);
|
||
|
ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
|
||
|
|
||
|
ASSERT(!pktq_full(pq));
|
||
|
ASSERT(!pktq_pfull(pq, prec));
|
||
|
|
||
|
q = &pq->q[prec];
|
||
|
|
||
|
if (q->head)
|
||
|
PKTSETLINK(q->tail, p);
|
||
|
else
|
||
|
q->head = p;
|
||
|
|
||
|
q->tail = p;
|
||
|
q->len++;
|
||
|
|
||
|
pq->len++;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
void * BCMFASTPATH
|
||
|
pktq_penq_head(struct pktq *pq, int prec, void *p)
|
||
|
{
|
||
|
struct pktq_prec *q;
|
||
|
|
||
|
/* 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);
|
||
|
ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
|
||
|
|
||
|
ASSERT(!pktq_full(pq));
|
||
|
ASSERT(!pktq_pfull(pq, prec));
|
||
|
|
||
|
q = &pq->q[prec];
|
||
|
|
||
|
if (q->head == NULL)
|
||
|
q->tail = p;
|
||
|
|
||
|
PKTSETLINK(p, q->head);
|
||
|
q->head = p;
|
||
|
q->len++;
|
||
|
|
||
|
pq->len++;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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[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];
|
||
|
|
||
|
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;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
void * BCMFASTPATH
|
||
|
pktq_pdeq(struct pktq *pq, int prec)
|
||
|
{
|
||
|
struct pktq_prec *q;
|
||
|
void *p;
|
||
|
|
||
|
/* 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;
|
||
|
|
||
|
if ((q->head = PKTLINK(p)) == NULL)
|
||
|
q->tail = NULL;
|
||
|
|
||
|
q->len--;
|
||
|
|
||
|
pq->len--;
|
||
|
|
||
|
PKTSETLINK(p, NULL);
|
||
|
|
||
|
done:
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void * BCMFASTPATH
|
||
|
pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p)
|
||
|
{
|
||
|
struct pktq_prec *q;
|
||
|
void *p = NULL;
|
||
|
|
||
|
/* 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 (prev_p == NULL)
|
||
|
goto done;
|
||
|
|
||
|
if ((p = PKTLINK(prev_p)) == NULL)
|
||
|
goto done;
|
||
|
|
||
|
q->len--;
|
||
|
|
||
|
pq->len--;
|
||
|
|
||
|
PKTSETLINK(prev_p, PKTLINK(p));
|
||
|
PKTSETLINK(p, NULL);
|
||
|
|
||
|
done:
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void * BCMFASTPATH
|
||
|
pktq_pdeq_with_fn(struct pktq *pq, int prec, 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 NULL;
|
||
|
|
||
|
ASSERT(prec >= 0 && prec < pq->num_prec);
|
||
|
|
||
|
q = &pq->q[prec];
|
||
|
p = q->head;
|
||
|
|
||
|
while (p) {
|
||
|
if (fn == NULL || (*fn)(p, arg)) {
|
||
|
break;
|
||
|
} else {
|
||
|
prev = p;
|
||
|
p = PKTLINK(p);
|
||
|
}
|
||
|
}
|
||
|
if (p == NULL)
|
||
|
goto done;
|
||
|
|
||
|
if (prev == NULL) {
|
||
|
if ((q->head = PKTLINK(p)) == NULL) {
|
||
|
q->tail = NULL;
|
||
|
}
|
||
|
} else {
|
||
|
PKTSETLINK(prev, PKTLINK(p));
|
||
|
if (q->tail == p) {
|
||
|
q->tail = prev;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
q->len--;
|
||
|
|
||
|
pq->len--;
|
||
|
|
||
|
PKTSETLINK(p, NULL);
|
||
|
|
||
|
done:
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->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->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, *next, *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) {
|
||
|
next = PKTLINK(p);
|
||
|
if (fn == NULL || (*fn)(p, arg)) {
|
||
|
bool head = (p == q->head);
|
||
|
if (head)
|
||
|
q->head = next;
|
||
|
else
|
||
|
PKTSETLINK(prev, next);
|
||
|
PKTSETLINK(p, NULL);
|
||
|
PKTFREE(osh, p, dir);
|
||
|
q->len--;
|
||
|
pq->len--;
|
||
|
} else {
|
||
|
prev = p;
|
||
|
}
|
||
|
p = next;
|
||
|
}
|
||
|
|
||
|
q->tail = prev;
|
||
|
|
||
|
if (q->head == NULL) {
|
||
|
ASSERT(q->len == 0);
|
||
|
ASSERT(q->tail == NULL);
|
||
|
}
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bool BCMFASTPATH
|
||
|
pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
|
||
|
{
|
||
|
bool ret = FALSE;
|
||
|
struct pktq_prec *q;
|
||
|
void *p = NULL;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return FALSE;
|
||
|
|
||
|
ASSERT(prec >= 0 && prec < pq->num_prec);
|
||
|
|
||
|
/* Should this just assert pktbuf? */
|
||
|
if (!pktbuf)
|
||
|
goto done;
|
||
|
|
||
|
q = &pq->q[prec];
|
||
|
|
||
|
if (q->head == pktbuf) {
|
||
|
if ((q->head = PKTLINK(pktbuf)) == NULL)
|
||
|
q->tail = NULL;
|
||
|
} else {
|
||
|
for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
|
||
|
;
|
||
|
if (p == NULL)
|
||
|
goto done;
|
||
|
|
||
|
PKTSETLINK(p, PKTLINK(pktbuf));
|
||
|
if (q->tail == pktbuf)
|
||
|
q->tail = p;
|
||
|
}
|
||
|
|
||
|
q->len--;
|
||
|
pq->len--;
|
||
|
PKTSETLINK(pktbuf, NULL);
|
||
|
ret = TRUE;
|
||
|
|
||
|
done:
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return FALSE;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
pktq_init(struct pktq *pq, int num_prec, int max_len)
|
||
|
{
|
||
|
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));
|
||
|
|
||
|
pq->num_prec = (uint16)num_prec;
|
||
|
|
||
|
pq->max = (uint16)max_len;
|
||
|
|
||
|
for (prec = 0; prec < num_prec; prec++)
|
||
|
pq->q[prec].max = pq->max;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
pktq_deinit(struct pktq *pq)
|
||
|
{
|
||
|
if (HND_PKTQ_MUTEX_DELETE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
pktq_set_max_plen(struct pktq *pq, int prec, int max_len)
|
||
|
{
|
||
|
ASSERT(prec >= 0 && prec < pq->num_prec);
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return;
|
||
|
|
||
|
if (prec < pq->num_prec)
|
||
|
pq->q[prec].max = (uint16)max_len;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void * BCMFASTPATH
|
||
|
pktq_deq(struct pktq *pq, int *prec_out)
|
||
|
{
|
||
|
struct pktq_prec *q;
|
||
|
void *p = NULL;
|
||
|
int prec;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
if (pq->len == 0)
|
||
|
goto done;
|
||
|
|
||
|
while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
|
||
|
pq->hi_prec--;
|
||
|
|
||
|
q = &pq->q[prec];
|
||
|
|
||
|
if ((p = q->head) == NULL)
|
||
|
goto done;
|
||
|
|
||
|
if ((q->head = PKTLINK(p)) == NULL)
|
||
|
q->tail = NULL;
|
||
|
|
||
|
q->len--;
|
||
|
|
||
|
pq->len--;
|
||
|
|
||
|
if (prec_out)
|
||
|
*prec_out = prec;
|
||
|
|
||
|
PKTSETLINK(p, NULL);
|
||
|
|
||
|
done:
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void * BCMFASTPATH
|
||
|
pktq_deq_tail(struct pktq *pq, int *prec_out)
|
||
|
{
|
||
|
struct pktq_prec *q;
|
||
|
void *p = NULL, *prev;
|
||
|
int prec;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
if (pq->len == 0)
|
||
|
goto done;
|
||
|
|
||
|
for (prec = 0; prec < pq->hi_prec; prec++)
|
||
|
if (pq->q[prec].head)
|
||
|
break;
|
||
|
|
||
|
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--;
|
||
|
|
||
|
if (prec_out)
|
||
|
*prec_out = prec;
|
||
|
|
||
|
PKTSETLINK(p, NULL);
|
||
|
|
||
|
done:
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
pktq_peek(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->len == 0)
|
||
|
goto done;
|
||
|
|
||
|
while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
|
||
|
pq->hi_prec--;
|
||
|
|
||
|
if (prec_out)
|
||
|
*prec_out = prec;
|
||
|
|
||
|
p = pq->q[prec].head;
|
||
|
|
||
|
done:
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->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->len == 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;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
|
||
|
{
|
||
|
int prec;
|
||
|
|
||
|
/* 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.
|
||
|
* pktq len of 0 means pktq's prec q's are all empty.
|
||
|
*/
|
||
|
if (pq->len == 0)
|
||
|
goto done;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/* Return sum of lengths of a specific set of precedences */
|
||
|
int
|
||
|
pktq_mlen(struct pktq *pq, uint prec_bmp)
|
||
|
{
|
||
|
int prec, len;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return 0;
|
||
|
|
||
|
len = 0;
|
||
|
|
||
|
for (prec = 0; prec <= pq->hi_prec; prec++)
|
||
|
if (prec_bmp & (1 << prec))
|
||
|
len += pq->q[prec].len;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return 0;
|
||
|
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
/* Priority peek from a specific set of precedences */
|
||
|
void * BCMFASTPATH
|
||
|
pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out)
|
||
|
{
|
||
|
struct pktq_prec *q;
|
||
|
void *p = NULL;
|
||
|
int prec;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
if (pq->len == 0)
|
||
|
goto done;
|
||
|
|
||
|
while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
|
||
|
pq->hi_prec--;
|
||
|
|
||
|
while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
|
||
|
if (prec-- == 0)
|
||
|
goto done;
|
||
|
|
||
|
q = &pq->q[prec];
|
||
|
|
||
|
if ((p = q->head) == NULL)
|
||
|
goto done;
|
||
|
|
||
|
if (prec_out)
|
||
|
*prec_out = prec;
|
||
|
|
||
|
done:
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
/* Priority dequeue from a specific set of precedences */
|
||
|
void * BCMFASTPATH
|
||
|
pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
|
||
|
{
|
||
|
struct pktq_prec *q;
|
||
|
void *p = NULL;
|
||
|
int prec;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
if (pq->len == 0)
|
||
|
goto done;
|
||
|
|
||
|
while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
|
||
|
pq->hi_prec--;
|
||
|
|
||
|
while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0))
|
||
|
if (prec-- == 0)
|
||
|
goto done;
|
||
|
|
||
|
q = &pq->q[prec];
|
||
|
|
||
|
if ((p = q->head) == NULL)
|
||
|
goto done;
|
||
|
|
||
|
if ((q->head = PKTLINK(p)) == NULL)
|
||
|
q->tail = NULL;
|
||
|
|
||
|
q->len--;
|
||
|
|
||
|
if (prec_out)
|
||
|
*prec_out = prec;
|
||
|
|
||
|
pq->len--;
|
||
|
|
||
|
PKTSETLINK(p, NULL);
|
||
|
|
||
|
done:
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return NULL;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
#ifdef HND_PKTQ_THREAD_SAFE
|
||
|
int
|
||
|
pktq_pavail(struct pktq *pq, int prec)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return 0;
|
||
|
|
||
|
ASSERT(prec >= 0 && prec < pq->num_prec);
|
||
|
|
||
|
ret = pq->q[prec].max - pq->q[prec].len;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return 0;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
pktq_pfull(struct pktq *pq, int prec)
|
||
|
{
|
||
|
bool ret;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return FALSE;
|
||
|
|
||
|
ASSERT(prec >= 0 && prec < pq->num_prec);
|
||
|
|
||
|
ret = pq->q[prec].len >= pq->q[prec].max;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return FALSE;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
pktq_avail(struct pktq *pq)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return 0;
|
||
|
|
||
|
ret = pq->max - pq->len;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return 0;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
pktq_full(struct pktq *pq)
|
||
|
{
|
||
|
bool ret;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
|
||
|
return FALSE;
|
||
|
|
||
|
ret = pq->len >= pq->max;
|
||
|
|
||
|
/* protect shared resource */
|
||
|
if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
|
||
|
return FALSE;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
#endif /* HND_PKTQ_THREAD_SAFE */
|