| /* |
| * HND generic pktq operation primitives |
| * |
| * 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 */ |