123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- /*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <linux/netdevice.h>
- #include <brcmu_utils.h>
- MODULE_AUTHOR("Broadcom Corporation");
- MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities.");
- MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
- MODULE_LICENSE("Dual BSD/GPL");
- struct sk_buff *brcmu_pkt_buf_get_skb(uint len)
- {
- struct sk_buff *skb;
- skb = dev_alloc_skb(len);
- if (skb) {
- skb_put(skb, len);
- skb->priority = 0;
- }
- return skb;
- }
- EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
- /* Free the driver packet. Free the tag if present */
- void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
- {
- struct sk_buff *nskb;
- int nest = 0;
- /* perversion: we use skb->next to chain multi-skb packets */
- while (skb) {
- nskb = skb->next;
- skb->next = NULL;
- if (skb->destructor)
- /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
- * destructor exists
- */
- dev_kfree_skb_any(skb);
- else
- /* can free immediately (even in_irq()) if destructor
- * does not exist
- */
- dev_kfree_skb(skb);
- nest++;
- skb = nskb;
- }
- }
- EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
- /* copy a buffer into a pkt buffer chain */
- uint brcmu_pktfrombuf(struct sk_buff *p, uint offset, int len,
- unsigned char *buf)
- {
- uint n, ret = 0;
- /* skip 'offset' bytes */
- for (; p && offset; p = p->next) {
- if (offset < (uint) (p->len))
- break;
- offset -= p->len;
- }
- if (!p)
- return 0;
- /* copy the data */
- for (; p && len; p = p->next) {
- n = min((uint) (p->len) - offset, (uint) len);
- memcpy(p->data + offset, buf, n);
- buf += n;
- len -= n;
- ret += n;
- offset = 0;
- }
- return ret;
- }
- EXPORT_SYMBOL(brcmu_pktfrombuf);
- /* return total length of buffer chain */
- uint brcmu_pkttotlen(struct sk_buff *p)
- {
- uint total;
- total = 0;
- for (; p; p = p->next)
- total += p->len;
- return total;
- }
- EXPORT_SYMBOL(brcmu_pkttotlen);
- /*
- * osl multiple-precedence packet queue
- * hi_prec is always >= the number of the highest non-empty precedence
- */
- struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
- struct sk_buff *p)
- {
- struct pktq_prec *q;
- if (pktq_full(pq) || pktq_pfull(pq, prec))
- return NULL;
- q = &pq->q[prec];
- if (q->head)
- q->tail->prev = p;
- else
- q->head = p;
- q->tail = p;
- q->len++;
- pq->len++;
- if (pq->hi_prec < prec)
- pq->hi_prec = (u8) prec;
- return p;
- }
- EXPORT_SYMBOL(brcmu_pktq_penq);
- struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
- struct sk_buff *p)
- {
- struct pktq_prec *q;
- if (pktq_full(pq) || pktq_pfull(pq, prec))
- return NULL;
- q = &pq->q[prec];
- if (q->head == NULL)
- q->tail = p;
- p->prev = q->head;
- q->head = p;
- q->len++;
- pq->len++;
- if (pq->hi_prec < prec)
- pq->hi_prec = (u8) prec;
- return p;
- }
- EXPORT_SYMBOL(brcmu_pktq_penq_head);
- struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
- {
- struct pktq_prec *q;
- struct sk_buff *p;
- q = &pq->q[prec];
- p = q->head;
- if (p == NULL)
- return NULL;
- q->head = p->prev;
- if (q->head == NULL)
- q->tail = NULL;
- q->len--;
- pq->len--;
- p->prev = NULL;
- return p;
- }
- EXPORT_SYMBOL(brcmu_pktq_pdeq);
- struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
- {
- struct pktq_prec *q;
- struct sk_buff *p, *prev;
- q = &pq->q[prec];
- p = q->head;
- if (p == NULL)
- return NULL;
- for (prev = NULL; p != q->tail; p = p->prev)
- prev = p;
- if (prev)
- prev->prev = NULL;
- else
- q->head = NULL;
- q->tail = prev;
- q->len--;
- pq->len--;
- return p;
- }
- EXPORT_SYMBOL(brcmu_pktq_pdeq_tail);
- void
- brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
- bool (*fn)(struct sk_buff *, void *), void *arg)
- {
- struct pktq_prec *q;
- struct sk_buff *p, *prev = NULL;
- q = &pq->q[prec];
- p = q->head;
- while (p) {
- if (fn == NULL || (*fn) (p, arg)) {
- bool head = (p == q->head);
- if (head)
- q->head = p->prev;
- else
- prev->prev = p->prev;
- p->prev = NULL;
- brcmu_pkt_buf_free_skb(p);
- q->len--;
- pq->len--;
- p = (head ? q->head : prev->prev);
- } else {
- prev = p;
- p = p->prev;
- }
- }
- if (q->head == NULL)
- q->tail = NULL;
- }
- EXPORT_SYMBOL(brcmu_pktq_pflush);
- void brcmu_pktq_flush(struct pktq *pq, bool dir,
- bool (*fn)(struct sk_buff *, void *), void *arg)
- {
- int prec;
- for (prec = 0; prec < pq->num_prec; prec++)
- brcmu_pktq_pflush(pq, prec, dir, fn, arg);
- }
- EXPORT_SYMBOL(brcmu_pktq_flush);
- void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len)
- {
- int prec;
- /* pq is variable size; only zero out what's requested */
- memset(pq, 0,
- offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
- pq->num_prec = (u16) num_prec;
- pq->max = (u16) max_len;
- for (prec = 0; prec < num_prec; prec++)
- pq->q[prec].max = pq->max;
- }
- EXPORT_SYMBOL(brcmu_pktq_init);
- struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out)
- {
- int prec;
- if (pq->len == 0)
- return NULL;
- for (prec = 0; prec < pq->hi_prec; prec++)
- if (pq->q[prec].head)
- break;
- if (prec_out)
- *prec_out = prec;
- return pq->q[prec].tail;
- }
- EXPORT_SYMBOL(brcmu_pktq_peek_tail);
- /* Return sum of lengths of a specific set of precedences */
- int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp)
- {
- int prec, len;
- len = 0;
- for (prec = 0; prec <= pq->hi_prec; prec++)
- if (prec_bmp & (1 << prec))
- len += pq->q[prec].len;
- return len;
- }
- EXPORT_SYMBOL(brcmu_pktq_mlen);
- /* Priority dequeue from a specific set of precedences */
- struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
- int *prec_out)
- {
- struct pktq_prec *q;
- struct sk_buff *p;
- int prec;
- if (pq->len == 0)
- return NULL;
- 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)
- return NULL;
- q = &pq->q[prec];
- p = q->head;
- if (p == NULL)
- return NULL;
- q->head = p->prev;
- if (q->head == NULL)
- q->tail = NULL;
- q->len--;
- if (prec_out)
- *prec_out = prec;
- pq->len--;
- p->prev = NULL;
- return p;
- }
- EXPORT_SYMBOL(brcmu_pktq_mdeq);
- #if defined(BCMDBG)
- /* pretty hex print a pkt buffer chain */
- void brcmu_prpkt(const char *msg, struct sk_buff *p0)
- {
- struct sk_buff *p;
- if (msg && (msg[0] != '\0'))
- printk(KERN_DEBUG "%s:\n", msg);
- for (p = p0; p; p = p->next)
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, p->data, p->len);
- }
- EXPORT_SYMBOL(brcmu_prpkt);
- #endif /* defined(BCMDBG) */
- /*
- * Traverse a string of 1-byte tag/1-byte length/variable-length value
- * triples, returning a pointer to the substring whose first element
- * matches tag
- */
- struct brcmu_tlv *brcmu_parse_tlvs(void *buf, int buflen, uint key)
- {
- struct brcmu_tlv *elt;
- int totlen;
- elt = (struct brcmu_tlv *) buf;
- totlen = buflen;
- /* find tagged parameter */
- while (totlen >= 2) {
- int len = elt->len;
- /* validate remaining totlen */
- if ((elt->id == key) && (totlen >= (len + 2)))
- return elt;
- elt = (struct brcmu_tlv *) ((u8 *) elt + (len + 2));
- totlen -= (len + 2);
- }
- return NULL;
- }
- EXPORT_SYMBOL(brcmu_parse_tlvs);
- #if defined(BCMDBG)
- int
- brcmu_format_flags(const struct brcmu_bit_desc *bd, u32 flags, char *buf,
- int len)
- {
- int i;
- char *p = buf;
- char hexstr[16];
- int slen = 0, nlen = 0;
- u32 bit;
- const char *name;
- if (len < 2 || !buf)
- return 0;
- buf[0] = '\0';
- for (i = 0; flags != 0; i++) {
- bit = bd[i].bit;
- name = bd[i].name;
- if (bit == 0 && flags != 0) {
- /* print any unnamed bits */
- snprintf(hexstr, 16, "0x%X", flags);
- name = hexstr;
- flags = 0; /* exit loop */
- } else if ((flags & bit) == 0)
- continue;
- flags &= ~bit;
- nlen = strlen(name);
- slen += nlen;
- /* count btwn flag space */
- if (flags != 0)
- slen += 1;
- /* need NULL char as well */
- if (len <= slen)
- break;
- /* copy NULL char but don't count it */
- strncpy(p, name, nlen + 1);
- p += nlen;
- /* copy btwn flag space and NULL char */
- if (flags != 0)
- p += snprintf(p, 2, " ");
- len -= slen;
- }
- /* indicate the str was too short */
- if (flags != 0) {
- if (len < 2)
- p -= 2 - len; /* overwrite last char */
- p += snprintf(p, 2, ">");
- }
- return (int)(p - buf);
- }
- EXPORT_SYMBOL(brcmu_format_flags);
- /*
- * print bytes formatted as hex to a string. return the resulting
- * string length
- */
- int brcmu_format_hex(char *str, const void *bytes, int len)
- {
- int i;
- char *p = str;
- const u8 *src = (const u8 *)bytes;
- for (i = 0; i < len; i++) {
- p += snprintf(p, 3, "%02X", *src);
- src++;
- }
- return (int)(p - str);
- }
- EXPORT_SYMBOL(brcmu_format_hex);
- #endif /* defined(BCMDBG) */
- char *brcmu_chipname(uint chipid, char *buf, uint len)
- {
- const char *fmt;
- fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
- snprintf(buf, len, fmt, chipid);
- return buf;
- }
- EXPORT_SYMBOL(brcmu_chipname);
- uint brcmu_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
- {
- uint len;
- len = strlen(name) + 1;
- if ((len + datalen) > buflen)
- return 0;
- strncpy(buf, name, buflen);
- /* append data onto the end of the name string */
- memcpy(&buf[len], data, datalen);
- len += datalen;
- return len;
- }
- EXPORT_SYMBOL(brcmu_mkiovar);
|