Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmutil/utils.c
178665 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2010 Broadcom Corporation3*/45#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt67#include <linux/netdevice.h>8#include <linux/module.h>9#if defined(__FreeBSD__)10#ifdef DEBUG11#include <linux/printk.h>12#endif13#endif1415#include <brcmu_utils.h>1617MODULE_AUTHOR("Broadcom Corporation");18MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities.");19MODULE_LICENSE("Dual BSD/GPL");20#if defined(__FreeBSD__)21MODULE_VERSION(brcmutil, 1);22MODULE_DEPEND(brcmutil, linuxkpi, 1, 1, 1);23#endif2425struct sk_buff *brcmu_pkt_buf_get_skb(uint len)26{27struct sk_buff *skb;2829skb = dev_alloc_skb(len);30if (skb) {31skb_put(skb, len);32skb->priority = 0;33}3435return skb;36}37EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);3839/* Free the driver packet. Free the tag if present */40void brcmu_pkt_buf_free_skb(struct sk_buff *skb)41{42if (!skb)43return;4445WARN_ON(skb->next);46dev_kfree_skb_any(skb);47}48EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);4950/*51* osl multiple-precedence packet queue52* hi_prec is always >= the number of the highest non-empty precedence53*/54struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,55struct sk_buff *p)56{57struct sk_buff_head *q;5859if (pktq_full(pq) || pktq_pfull(pq, prec))60return NULL;6162q = &pq->q[prec].skblist;63skb_queue_tail(q, p);64pq->len++;6566if (pq->hi_prec < prec)67pq->hi_prec = (u8) prec;6869return p;70}71EXPORT_SYMBOL(brcmu_pktq_penq);7273struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,74struct sk_buff *p)75{76struct sk_buff_head *q;7778if (pktq_full(pq) || pktq_pfull(pq, prec))79return NULL;8081q = &pq->q[prec].skblist;82skb_queue_head(q, p);83pq->len++;8485if (pq->hi_prec < prec)86pq->hi_prec = (u8) prec;8788return p;89}90EXPORT_SYMBOL(brcmu_pktq_penq_head);9192struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)93{94struct sk_buff_head *q;95struct sk_buff *p;9697q = &pq->q[prec].skblist;98p = skb_dequeue(q);99if (p == NULL)100return NULL;101102pq->len--;103return p;104}105EXPORT_SYMBOL(brcmu_pktq_pdeq);106107/*108* precedence based dequeue with match function. Passing a NULL pointer109* for the match function parameter is considered to be a wildcard so110* any packet on the queue is returned. In that case it is no different111* from brcmu_pktq_pdeq() above.112*/113struct sk_buff *brcmu_pktq_pdeq_match(struct pktq *pq, int prec,114bool (*match_fn)(struct sk_buff *skb,115void *arg), void *arg)116{117struct sk_buff_head *q;118struct sk_buff *p, *next;119120q = &pq->q[prec].skblist;121skb_queue_walk_safe(q, p, next) {122if (match_fn == NULL || match_fn(p, arg)) {123skb_unlink(p, q);124pq->len--;125return p;126}127}128return NULL;129}130EXPORT_SYMBOL(brcmu_pktq_pdeq_match);131132struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)133{134struct sk_buff_head *q;135struct sk_buff *p;136137q = &pq->q[prec].skblist;138p = skb_dequeue_tail(q);139if (p == NULL)140return NULL;141142pq->len--;143return p;144}145EXPORT_SYMBOL(brcmu_pktq_pdeq_tail);146147void148brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,149bool (*fn)(struct sk_buff *, void *), void *arg)150{151struct sk_buff_head *q;152struct sk_buff *p, *next;153154q = &pq->q[prec].skblist;155skb_queue_walk_safe(q, p, next) {156if (fn == NULL || (*fn) (p, arg)) {157skb_unlink(p, q);158brcmu_pkt_buf_free_skb(p);159pq->len--;160}161}162}163EXPORT_SYMBOL(brcmu_pktq_pflush);164165void brcmu_pktq_flush(struct pktq *pq, bool dir,166bool (*fn)(struct sk_buff *, void *), void *arg)167{168int prec;169for (prec = 0; prec < pq->num_prec; prec++)170brcmu_pktq_pflush(pq, prec, dir, fn, arg);171}172EXPORT_SYMBOL(brcmu_pktq_flush);173174void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len)175{176int prec;177178/* pq is variable size; only zero out what's requested */179memset(pq, 0,180offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));181182pq->num_prec = (u16) num_prec;183184pq->max = (u16) max_len;185186for (prec = 0; prec < num_prec; prec++) {187pq->q[prec].max = pq->max;188skb_queue_head_init(&pq->q[prec].skblist);189}190}191EXPORT_SYMBOL(brcmu_pktq_init);192193struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out)194{195int prec;196197if (pktq_empty(pq))198return NULL;199200for (prec = 0; prec < pq->hi_prec; prec++)201if (!skb_queue_empty(&pq->q[prec].skblist))202break;203204if (prec_out)205*prec_out = prec;206207return skb_peek_tail(&pq->q[prec].skblist);208}209EXPORT_SYMBOL(brcmu_pktq_peek_tail);210211/* Return sum of lengths of a specific set of precedences */212int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp)213{214int prec, len;215216len = 0;217218for (prec = 0; prec <= pq->hi_prec; prec++)219if (prec_bmp & (1 << prec))220len += pq->q[prec].skblist.qlen;221222return len;223}224EXPORT_SYMBOL(brcmu_pktq_mlen);225226/* Priority dequeue from a specific set of precedences */227struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,228int *prec_out)229{230struct sk_buff_head *q;231struct sk_buff *p;232int prec;233234if (pktq_empty(pq))235return NULL;236237while ((prec = pq->hi_prec) > 0 &&238skb_queue_empty(&pq->q[prec].skblist))239pq->hi_prec--;240241while ((prec_bmp & (1 << prec)) == 0 ||242skb_queue_empty(&pq->q[prec].skblist))243if (prec-- == 0)244return NULL;245246q = &pq->q[prec].skblist;247p = skb_dequeue(q);248if (p == NULL)249return NULL;250251pq->len--;252253if (prec_out)254*prec_out = prec;255256return p;257}258EXPORT_SYMBOL(brcmu_pktq_mdeq);259260/* Produce a human-readable string for boardrev */261char *brcmu_boardrev_str(u32 brev, char *buf)262{263char c;264265if (brev < 0x100) {266snprintf(buf, BRCMU_BOARDREV_LEN, "%d.%d",267(brev & 0xf0) >> 4, brev & 0xf);268} else {269c = (brev & 0xf000) == 0x1000 ? 'P' : 'A';270snprintf(buf, BRCMU_BOARDREV_LEN, "%c%03x", c, brev & 0xfff);271}272return buf;273}274EXPORT_SYMBOL(brcmu_boardrev_str);275276char *brcmu_dotrev_str(u32 dotrev, char *buf)277{278u8 dotval[4];279280if (!dotrev) {281snprintf(buf, BRCMU_DOTREV_LEN, "unknown");282return buf;283}284dotval[0] = (dotrev >> 24) & 0xFF;285dotval[1] = (dotrev >> 16) & 0xFF;286dotval[2] = (dotrev >> 8) & 0xFF;287dotval[3] = dotrev & 0xFF;288289if (dotval[3])290snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d.%d", dotval[0],291dotval[1], dotval[2], dotval[3]);292else if (dotval[2])293snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d", dotval[0],294dotval[1], dotval[2]);295else296snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d", dotval[0],297dotval[1]);298299return buf;300}301EXPORT_SYMBOL(brcmu_dotrev_str);302303#if defined(DEBUG)304/* pretty hex print a pkt buffer chain */305void brcmu_prpkt(const char *msg, struct sk_buff *p0)306{307struct sk_buff *p;308309if (msg && (msg[0] != '\0'))310pr_debug("%s:\n", msg);311312for (p = p0; p; p = p->next)313print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, p->data, p->len);314}315EXPORT_SYMBOL(brcmu_prpkt);316317void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...)318{319struct va_format vaf;320va_list args;321322va_start(args, fmt);323324vaf.fmt = fmt;325vaf.va = &args;326327pr_debug("%pV", &vaf);328329va_end(args);330331print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, size);332}333EXPORT_SYMBOL(brcmu_dbg_hex_dump);334335#endif /* defined(DEBUG) */336337338