2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/ctype.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <linux/module.h>
21 #include <linux/pci.h>
22 #include <linux/netdevice.h>
23 #include <linux/sched.h>
24 #include <linux/printk.h>
31 MODULE_AUTHOR("Broadcom Corporation");
32 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities.");
33 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
34 MODULE_LICENSE("Dual BSD/GPL");
36 struct sk_buff
*bcm_pkt_buf_get_skb(uint len
)
40 skb
= dev_alloc_skb(len
);
48 EXPORT_SYMBOL(bcm_pkt_buf_get_skb
);
50 /* Free the driver packet. Free the tag if present */
51 void bcm_pkt_buf_free_skb(struct sk_buff
*skb
)
56 /* perversion: we use skb->next to chain multi-skb packets */
62 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
65 dev_kfree_skb_any(skb
);
67 /* can free immediately (even in_irq()) if destructor
76 EXPORT_SYMBOL(bcm_pkt_buf_free_skb
);
79 /* copy a buffer into a pkt buffer chain */
80 uint
bcm_pktfrombuf(struct sk_buff
*p
, uint offset
, int len
,
85 /* skip 'offset' bytes */
86 for (; p
&& offset
; p
= p
->next
) {
87 if (offset
< (uint
) (p
->len
))
96 for (; p
&& len
; p
= p
->next
) {
97 n
= min((uint
) (p
->len
) - offset
, (uint
) len
);
98 memcpy(p
->data
+ offset
, buf
, n
);
107 EXPORT_SYMBOL(bcm_pktfrombuf
);
109 /* return total length of buffer chain */
110 uint
bcm_pkttotlen(struct sk_buff
*p
)
115 for (; p
; p
= p
->next
)
119 EXPORT_SYMBOL(bcm_pkttotlen
);
122 * osl multiple-precedence packet queue
123 * hi_prec is always >= the number of the highest non-empty precedence
125 struct sk_buff
*bcm_pktq_penq(struct pktq
*pq
, int prec
,
130 if (pktq_full(pq
) || pktq_pfull(pq
, prec
))
145 if (pq
->hi_prec
< prec
)
146 pq
->hi_prec
= (u8
) prec
;
150 EXPORT_SYMBOL(bcm_pktq_penq
);
152 struct sk_buff
*bcm_pktq_penq_head(struct pktq
*pq
, int prec
,
157 if (pktq_full(pq
) || pktq_pfull(pq
, prec
))
171 if (pq
->hi_prec
< prec
)
172 pq
->hi_prec
= (u8
) prec
;
176 EXPORT_SYMBOL(bcm_pktq_penq_head
);
178 struct sk_buff
*bcm_pktq_pdeq(struct pktq
*pq
, int prec
)
201 EXPORT_SYMBOL(bcm_pktq_pdeq
);
203 struct sk_buff
*bcm_pktq_pdeq_tail(struct pktq
*pq
, int prec
)
206 struct sk_buff
*p
, *prev
;
214 for (prev
= NULL
; p
!= q
->tail
; p
= p
->prev
)
229 EXPORT_SYMBOL(bcm_pktq_pdeq_tail
);
232 bcm_pktq_pflush(struct pktq
*pq
, int prec
, bool dir
,
233 ifpkt_cb_t fn
, void *arg
)
236 struct sk_buff
*p
, *prev
= NULL
;
241 if (fn
== NULL
|| (*fn
) (p
, arg
)) {
242 bool head
= (p
== q
->head
);
246 prev
->prev
= p
->prev
;
248 bcm_pkt_buf_free_skb(p
);
251 p
= (head
? q
->head
: prev
->prev
);
258 if (q
->head
== NULL
) {
262 EXPORT_SYMBOL(bcm_pktq_pflush
);
264 void bcm_pktq_flush(struct pktq
*pq
, bool dir
,
265 ifpkt_cb_t fn
, void *arg
)
268 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
269 bcm_pktq_pflush(pq
, prec
, dir
, fn
, arg
);
271 EXPORT_SYMBOL(bcm_pktq_flush
);
273 void bcm_pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
277 /* pq is variable size; only zero out what's requested */
279 offsetof(struct pktq
, q
) + (sizeof(struct pktq_prec
) * num_prec
));
281 pq
->num_prec
= (u16
) num_prec
;
283 pq
->max
= (u16
) max_len
;
285 for (prec
= 0; prec
< num_prec
; prec
++)
286 pq
->q
[prec
].max
= pq
->max
;
288 EXPORT_SYMBOL(bcm_pktq_init
);
290 struct sk_buff
*bcm_pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
297 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
298 if (pq
->q
[prec
].head
)
304 return pq
->q
[prec
].tail
;
306 EXPORT_SYMBOL(bcm_pktq_peek_tail
);
308 /* Return sum of lengths of a specific set of precedences */
309 int bcm_pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
315 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
316 if (prec_bmp
& (1 << prec
))
317 len
+= pq
->q
[prec
].len
;
321 EXPORT_SYMBOL(bcm_pktq_mlen
);
323 /* Priority dequeue from a specific set of precedences */
324 struct sk_buff
*bcm_pktq_mdeq(struct pktq
*pq
, uint prec_bmp
,
334 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
337 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
362 EXPORT_SYMBOL(bcm_pktq_mdeq
);
364 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
365 int bcm_ether_atoe(char *p
, u8
*ea
)
370 ea
[i
++] = (char)simple_strtoul(p
, &p
, 16);
377 EXPORT_SYMBOL(bcm_ether_atoe
);
380 /* pretty hex print a pkt buffer chain */
381 void bcm_prpkt(const char *msg
, struct sk_buff
*p0
)
385 if (msg
&& (msg
[0] != '\0'))
386 printk(KERN_DEBUG
"%s:\n", msg
);
388 for (p
= p0
; p
; p
= p
->next
)
389 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
, p
->data
, p
->len
);
391 EXPORT_SYMBOL(bcm_prpkt
);
392 #endif /* defined(BCMDBG) */
394 /* iovar table lookup */
395 const bcm_iovar_t
*bcm_iovar_lookup(const bcm_iovar_t
*table
, const char *name
)
397 const bcm_iovar_t
*vi
;
398 const char *lookup_name
;
400 /* skip any ':' delimited option prefixes */
401 lookup_name
= strrchr(name
, ':');
402 if (lookup_name
!= NULL
)
407 for (vi
= table
; vi
->name
; vi
++) {
408 if (!strcmp(vi
->name
, lookup_name
))
411 /* ran to end of table */
413 return NULL
; /* var name not found */
415 EXPORT_SYMBOL(bcm_iovar_lookup
);
417 int bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
421 /* length check on io buf */
430 /* all integers are s32 sized args at the ioctl interface */
431 if (len
< (int)sizeof(int)) {
432 bcmerror
= -EOVERFLOW
;
437 /* buffer must meet minimum length requirement */
438 if (len
< vi
->minlen
) {
439 bcmerror
= -EOVERFLOW
;
445 /* Cannot return nil... */
446 bcmerror
= -ENOTSUPP
;
448 /* Set is an action w/o parameters */
454 /* unknown type for length check in iovar info */
455 bcmerror
= -ENOTSUPP
;
460 EXPORT_SYMBOL(bcm_iovar_lencheck
);
462 /*******************************************************************************
465 * Computes a crc8 over the input data using the polynomial:
467 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
469 * The caller provides the initial value (either CRC8_INIT_VALUE
470 * or the previous returned value) to allow for processing of
471 * discontiguous blocks of data. When generating the CRC the
472 * caller is responsible for complementing the final return value
473 * and inserting it into the byte stream. When checking, a final
474 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
476 * Reference: Dallas Semiconductor Application Note 27
477 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
478 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
479 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
481 * ****************************************************************************
484 static const u8 crc8_table
[256] = {
485 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
486 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
487 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
488 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
489 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
490 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
491 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
492 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
493 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
494 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
495 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
496 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
497 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
498 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
499 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
500 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
501 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
502 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
503 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
504 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
505 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
506 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
507 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
508 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
509 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
510 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
511 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
512 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
513 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
514 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
515 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
516 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
519 u8
bcm_crc8(u8
*pdata
, /* pointer to array of data to process */
520 uint nbytes
, /* number of input data bytes to process */
521 u8 crc
/* either CRC8_INIT_VALUE or previous return value */
523 /* loop over the buffer data */
525 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
529 EXPORT_SYMBOL(bcm_crc8
);
532 * Traverse a string of 1-byte tag/1-byte length/variable-length value
533 * triples, returning a pointer to the substring whose first element
536 bcm_tlv_t
*bcm_parse_tlvs(void *buf
, int buflen
, uint key
)
541 elt
= (bcm_tlv_t
*) buf
;
544 /* find tagged parameter */
545 while (totlen
>= 2) {
548 /* validate remaining totlen */
549 if ((elt
->id
== key
) && (totlen
>= (len
+ 2)))
552 elt
= (bcm_tlv_t
*) ((u8
*) elt
+ (len
+ 2));
558 EXPORT_SYMBOL(bcm_parse_tlvs
);
563 bcm_format_flags(const bcm_bit_desc_t
*bd
, u32 flags
, char *buf
, int len
)
568 int slen
= 0, nlen
= 0;
577 for (i
= 0; flags
!= 0; i
++) {
580 if (bit
== 0 && flags
!= 0) {
581 /* print any unnamed bits */
582 snprintf(hexstr
, 16, "0x%X", flags
);
584 flags
= 0; /* exit loop */
585 } else if ((flags
& bit
) == 0)
590 /* count btwn flag space */
593 /* need NULL char as well */
596 /* copy NULL char but don't count it */
597 strncpy(p
, name
, nlen
+ 1);
599 /* copy btwn flag space and NULL char */
601 p
+= snprintf(p
, 2, " ");
605 /* indicate the str was too short */
608 p
-= 2 - len
; /* overwrite last char */
609 p
+= snprintf(p
, 2, ">");
612 return (int)(p
- buf
);
614 EXPORT_SYMBOL(bcm_format_flags
);
616 /* print bytes formatted as hex to a string. return the resulting string length */
617 int bcm_format_hex(char *str
, const void *bytes
, int len
)
621 const u8
*src
= (const u8
*)bytes
;
623 for (i
= 0; i
< len
; i
++) {
624 p
+= snprintf(p
, 3, "%02X", *src
);
627 return (int)(p
- str
);
629 EXPORT_SYMBOL(bcm_format_hex
);
630 #endif /* defined(BCMDBG) */
632 char *bcm_chipname(uint chipid
, char *buf
, uint len
)
636 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
637 snprintf(buf
, len
, fmt
, chipid
);
640 EXPORT_SYMBOL(bcm_chipname
);
642 uint
bcm_mkiovar(char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
646 len
= strlen(name
) + 1;
648 if ((len
+ datalen
) > buflen
)
651 strncpy(buf
, name
, buflen
);
653 /* append data onto the end of the name string */
654 memcpy(&buf
[len
], data
, datalen
);
659 EXPORT_SYMBOL(bcm_mkiovar
);
661 /* Quarter dBm units to mW
662 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
663 * Table is offset so the last entry is largest mW value that fits in
667 #define QDBM_OFFSET 153 /* Offset for first entry */
668 #define QDBM_TABLE_LEN 40 /* Table size */
670 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
671 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
673 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
675 /* Largest mW value that will round down to the last table entry,
676 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
677 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
678 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
680 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
682 static const u16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
683 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
684 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
685 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
686 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
687 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
688 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
691 u16
bcm_qdbm_to_mw(u8 qdbm
)
694 int idx
= qdbm
- QDBM_OFFSET
;
696 if (idx
>= QDBM_TABLE_LEN
) {
697 /* clamp to max u16 mW value */
701 /* scale the qdBm index up to the range of the table 0-40
702 * where an offset of 40 qdBm equals a factor of 10 mW.
709 /* return the mW value scaled down to the correct factor of 10,
710 * adding in factor/2 to get proper rounding.
712 return (nqdBm_to_mW_map
[idx
] + factor
/ 2) / factor
;
714 EXPORT_SYMBOL(bcm_qdbm_to_mw
);
716 u8
bcm_mw_to_qdbm(u16 mw
)
723 /* handle boundary case */
727 offset
= QDBM_OFFSET
;
729 /* move mw into the range of the table */
730 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
735 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
- 1; qdbm
++) {
736 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+ 1] -
737 nqdBm_to_mW_map
[qdbm
]) / 2;
738 if (mw_uint
< boundary
)
746 EXPORT_SYMBOL(bcm_mw_to_qdbm
);
748 uint
bcm_bitcount(u8
*bitmap
, uint length
)
750 uint bitcount
= 0, i
;
752 for (i
= 0; i
< length
; i
++) {
761 EXPORT_SYMBOL(bcm_bitcount
);
763 /* Initialization of bcmstrbuf structure */
764 void bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
766 b
->origsize
= b
->size
= size
;
767 b
->origbuf
= b
->buf
= buf
;
769 EXPORT_SYMBOL(bcm_binit
);
771 /* Buffer sprintf wrapper to guard against buffer overflow */
772 int bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
778 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
780 /* Non Ansi C99 compliant returns -1,
781 * Ansi compliant return r >= b->size,
782 * bcmstdlib returns 0, handle all
784 if ((r
== -1) || (r
>= (int)b
->size
) || (r
== 0)) {
795 EXPORT_SYMBOL(bcm_bprintf
);