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>
22 #include <linux/module.h>
23 #include <linux/pci.h>
24 #include <linux/netdevice.h>
29 #include <bcmendian.h>
31 #include <proto/802.1d.h>
32 #include <proto/802.11.h>
34 /* copy a buffer into a pkt buffer chain */
35 uint
pktfrombuf(struct osl_info
*osh
, struct sk_buff
*p
, uint offset
, int len
,
40 /* skip 'offset' bytes */
41 for (; p
&& offset
; p
= p
->next
) {
42 if (offset
< (uint
) (p
->len
))
51 for (; p
&& len
; p
= p
->next
) {
52 n
= min((uint
) (p
->len
) - offset
, (uint
) len
);
53 bcopy(buf
, p
->data
+ offset
, n
);
62 /* return total length of buffer chain */
63 uint BCMFASTPATH
pkttotlen(struct osl_info
*osh
, struct sk_buff
*p
)
68 for (; p
; p
= p
->next
)
74 * osl multiple-precedence packet queue
75 * hi_prec is always >= the number of the highest non-empty precedence
77 struct sk_buff
*BCMFASTPATH
pktq_penq(struct pktq
*pq
, int prec
,
82 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
83 ASSERT(p
->prev
== NULL
); /* queueing chains not allowed */
85 ASSERT(!pktq_full(pq
));
86 ASSERT(!pktq_pfull(pq
, prec
));
100 if (pq
->hi_prec
< prec
)
101 pq
->hi_prec
= (u8
) prec
;
106 struct sk_buff
*BCMFASTPATH
pktq_penq_head(struct pktq
*pq
, int prec
,
111 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
112 ASSERT(p
->prev
== NULL
); /* queueing chains not allowed */
114 ASSERT(!pktq_full(pq
));
115 ASSERT(!pktq_pfull(pq
, prec
));
128 if (pq
->hi_prec
< prec
)
129 pq
->hi_prec
= (u8
) prec
;
134 struct sk_buff
*BCMFASTPATH
pktq_pdeq(struct pktq
*pq
, int prec
)
139 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
160 struct sk_buff
*BCMFASTPATH
pktq_pdeq_tail(struct pktq
*pq
, int prec
)
163 struct sk_buff
*p
, *prev
;
165 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
173 for (prev
= NULL
; p
!= q
->tail
; p
= p
->prev
)
190 void pktq_pflush(struct osl_info
*osh
, struct pktq
*pq
, int prec
, bool dir
)
200 pkt_buf_free_skb(osh
, p
, dir
);
209 void pktq_flush(struct osl_info
*osh
, struct pktq
*pq
, bool dir
)
212 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
213 pktq_pflush(osh
, pq
, prec
, dir
);
214 ASSERT(pq
->len
== 0);
216 #else /* !BRCM_FULLMAC */
217 /* TODO: can we remove callback for softmac? */
219 pktq_pflush(struct osl_info
*osh
, struct pktq
*pq
, int prec
, bool dir
,
220 ifpkt_cb_t fn
, int arg
)
223 struct sk_buff
*p
, *prev
= NULL
;
228 if (fn
== NULL
|| (*fn
) (p
, arg
)) {
229 bool head
= (p
== q
->head
);
233 prev
->prev
= p
->prev
;
235 pkt_buf_free_skb(osh
, p
, dir
);
238 p
= (head
? q
->head
: prev
->prev
);
245 if (q
->head
== NULL
) {
251 void pktq_flush(struct osl_info
*osh
, struct pktq
*pq
, bool dir
,
252 ifpkt_cb_t fn
, int arg
)
255 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
256 pktq_pflush(osh
, pq
, prec
, dir
, fn
, arg
);
258 ASSERT(pq
->len
== 0);
260 #endif /* BRCM_FULLMAC */
262 void pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
266 ASSERT(num_prec
> 0 && num_prec
<= PKTQ_MAX_PREC
);
268 /* pq is variable size; only zero out what's requested */
270 offsetof(struct pktq
, q
) + (sizeof(struct pktq_prec
) * num_prec
));
272 pq
->num_prec
= (u16
) num_prec
;
274 pq
->max
= (u16
) max_len
;
276 for (prec
= 0; prec
< num_prec
; prec
++)
277 pq
->q
[prec
].max
= pq
->max
;
280 struct sk_buff
*pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
287 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
288 if (pq
->q
[prec
].head
)
294 return pq
->q
[prec
].tail
;
297 /* Return sum of lengths of a specific set of precedences */
298 int pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
304 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
305 if (prec_bmp
& (1 << prec
))
306 len
+= pq
->q
[prec
].len
;
310 /* Priority dequeue from a specific set of precedences */
311 struct sk_buff
*BCMFASTPATH
pktq_mdeq(struct pktq
*pq
, uint prec_bmp
,
321 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
324 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
350 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
351 int bcm_ether_atoe(char *p
, u8
*ea
)
356 ea
[i
++] = (char)simple_strtoul(p
, &p
, 16);
365 * Search the name=value vars for a specific one and return its value.
366 * Returns NULL if not found.
368 char *getvar(char *vars
, const char *name
)
380 /* first look in vars[] */
381 for (s
= vars
; s
&& *s
;) {
382 if ((memcmp(s
, name
, len
) == 0) && (s
[len
] == '='))
391 /* then query nvram */
392 return nvram_get(name
);
397 * Search the vars for a specific one and return its value as
398 * an integer. Returns 0 if not found.
400 int getintvar(char *vars
, const char *name
)
404 val
= getvar(vars
, name
);
408 return simple_strtoul(val
, NULL
, 0);
412 /* pretty hex print a pkt buffer chain */
413 void prpkt(const char *msg
, struct osl_info
*osh
, struct sk_buff
*p0
)
417 if (msg
&& (msg
[0] != '\0'))
418 printf("%s:\n", msg
);
420 for (p
= p0
; p
; p
= p
->next
)
421 prhex(NULL
, p
->data
, p
->len
);
423 #endif /* defined(BCMDBG) */
425 static char bcm_undeferrstr
[BCME_STRLEN
];
427 static const char *bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
429 /* Convert the error codes into related error strings */
430 const char *bcmerrorstr(int bcmerror
)
432 /* check if someone added a bcmerror code but
433 forgot to add errorstring */
434 ASSERT(ABS(BCME_LAST
) == (ARRAY_SIZE(bcmerrorstrtable
) - 1));
436 if (bcmerror
> 0 || bcmerror
< BCME_LAST
) {
437 snprintf(bcm_undeferrstr
, BCME_STRLEN
, "Undefined error %d",
439 return bcm_undeferrstr
;
442 ASSERT(strlen(bcmerrorstrtable
[-bcmerror
]) < BCME_STRLEN
);
444 return bcmerrorstrtable
[-bcmerror
];
447 /* iovar table lookup */
448 const bcm_iovar_t
*bcm_iovar_lookup(const bcm_iovar_t
*table
, const char *name
)
450 const bcm_iovar_t
*vi
;
451 const char *lookup_name
;
453 /* skip any ':' delimited option prefixes */
454 lookup_name
= strrchr(name
, ':');
455 if (lookup_name
!= NULL
)
460 ASSERT(table
!= NULL
);
462 for (vi
= table
; vi
->name
; vi
++) {
463 if (!strcmp(vi
->name
, lookup_name
))
466 /* ran to end of table */
468 return NULL
; /* var name not found */
471 int bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
475 /* length check on io buf */
484 /* all integers are s32 sized args at the ioctl interface */
485 if (len
< (int)sizeof(int)) {
486 bcmerror
= BCME_BUFTOOSHORT
;
491 /* buffer must meet minimum length requirement */
492 if (len
< vi
->minlen
) {
493 bcmerror
= BCME_BUFTOOSHORT
;
499 /* Cannot return nil... */
500 bcmerror
= BCME_UNSUPPORTED
;
502 /* Set is an action w/o parameters */
503 bcmerror
= BCME_BUFTOOLONG
;
508 /* unknown type for length check in iovar info */
510 bcmerror
= BCME_UNSUPPORTED
;
516 /*******************************************************************************
519 * Computes a crc8 over the input data using the polynomial:
521 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
523 * The caller provides the initial value (either CRC8_INIT_VALUE
524 * or the previous returned value) to allow for processing of
525 * discontiguous blocks of data. When generating the CRC the
526 * caller is responsible for complementing the final return value
527 * and inserting it into the byte stream. When checking, a final
528 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
530 * Reference: Dallas Semiconductor Application Note 27
531 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
532 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
533 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
535 * ****************************************************************************
538 static const u8 crc8_table
[256] = {
539 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
540 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
541 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
542 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
543 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
544 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
545 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
546 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
547 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
548 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
549 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
550 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
551 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
552 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
553 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
554 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
555 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
556 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
557 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
558 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
559 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
560 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
561 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
562 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
563 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
564 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
565 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
566 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
567 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
568 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
569 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
570 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
573 #define CRC_INNER_LOOP(n, c, x) \
574 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
576 u8
hndcrc8(u8
*pdata
, /* pointer to array of data to process */
577 uint nbytes
, /* number of input data bytes to process */
578 u8 crc
/* either CRC8_INIT_VALUE or previous return value */
580 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
581 * to avoid the undefined and unnecessary (u8 >> 8) operation.
584 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
589 /*******************************************************************************
592 * Computes a crc16 over the input data using the polynomial:
594 * x^16 + x^12 +x^5 + 1
596 * The caller provides the initial value (either CRC16_INIT_VALUE
597 * or the previous returned value) to allow for processing of
598 * discontiguous blocks of data. When generating the CRC the
599 * caller is responsible for complementing the final return value
600 * and inserting it into the byte stream. When checking, a final
601 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
603 * Reference: Dallas Semiconductor Application Note 27
604 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
605 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
606 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
608 * ****************************************************************************
611 static const u16 crc16_table
[256] = {
612 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
613 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
614 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
615 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
616 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
617 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
618 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
619 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
620 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
621 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
622 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
623 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
624 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
625 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
626 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
627 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
628 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
629 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
630 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
631 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
632 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
633 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
634 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
635 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
636 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
637 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
638 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
639 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
640 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
641 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
642 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
643 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
646 u16
hndcrc16(u8
*pdata
, /* pointer to array of data to process */
647 uint nbytes
, /* number of input data bytes to process */
648 u16 crc
/* either CRC16_INIT_VALUE or previous return value */
651 CRC_INNER_LOOP(16, crc
, *pdata
++);
655 static const u32 crc32_table
[256] = {
656 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
657 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
658 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
659 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
660 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
661 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
662 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
663 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
664 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
665 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
666 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
667 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
668 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
669 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
670 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
671 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
672 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
673 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
674 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
675 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
676 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
677 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
678 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
679 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
680 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
681 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
682 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
683 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
684 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
685 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
686 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
687 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
688 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
689 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
690 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
691 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
692 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
693 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
694 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
695 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
696 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
697 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
698 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
699 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
700 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
701 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
702 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
703 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
704 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
705 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
706 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
707 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
708 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
709 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
710 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
711 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
712 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
713 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
714 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
715 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
716 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
717 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
718 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
719 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
722 u32
hndcrc32(u8
*pdata
, /* pointer to array of data to process */
723 uint nbytes
, /* number of input data bytes to process */
724 u32 crc
/* either CRC32_INIT_VALUE or previous
731 unsigned long *tptr
= (unsigned long *) tmp
;
733 /* in case the beginning of the buffer isn't aligned */
734 pend
= (u8
*) ((uint
) (pdata
+ 3) & 0xfffffffc);
735 nbytes
-= (pend
- pdata
);
737 CRC_INNER_LOOP(32, crc
, *pdata
++);
739 /* handle bulk of data as 32-bit words */
740 pend
= pdata
+ (nbytes
& 0xfffffffc);
741 while (pdata
< pend
) {
742 *tptr
= *(unsigned long *) pdata
;
743 pdata
+= sizeof(unsigned long *);
744 CRC_INNER_LOOP(32, crc
, tmp
[0]);
745 CRC_INNER_LOOP(32, crc
, tmp
[1]);
746 CRC_INNER_LOOP(32, crc
, tmp
[2]);
747 CRC_INNER_LOOP(32, crc
, tmp
[3]);
750 /* 1-3 bytes at end of buffer */
751 pend
= pdata
+ (nbytes
& 0x03);
753 CRC_INNER_LOOP(32, crc
, *pdata
++);
755 pend
= pdata
+ nbytes
;
757 CRC_INNER_LOOP(32, crc
, *pdata
++);
758 #endif /* __mips__ */
763 * Traverse a string of 1-byte tag/1-byte length/variable-length value
764 * triples, returning a pointer to the substring whose first element
767 bcm_tlv_t
*bcm_parse_tlvs(void *buf
, int buflen
, uint key
)
772 elt
= (bcm_tlv_t
*) buf
;
775 /* find tagged parameter */
776 while (totlen
>= 2) {
779 /* validate remaining totlen */
780 if ((elt
->id
== key
) && (totlen
>= (len
+ 2)))
783 elt
= (bcm_tlv_t
*) ((u8
*) elt
+ (len
+ 2));
793 bcm_format_flags(const bcm_bit_desc_t
*bd
, u32 flags
, char *buf
, int len
)
798 int slen
= 0, nlen
= 0;
807 for (i
= 0; flags
!= 0; i
++) {
810 if (bit
== 0 && flags
!= 0) {
811 /* print any unnamed bits */
812 snprintf(hexstr
, 16, "0x%X", flags
);
814 flags
= 0; /* exit loop */
815 } else if ((flags
& bit
) == 0)
820 /* count btwn flag space */
823 /* need NULL char as well */
826 /* copy NULL char but don't count it */
827 strncpy(p
, name
, nlen
+ 1);
829 /* copy btwn flag space and NULL char */
831 p
+= snprintf(p
, 2, " ");
835 /* indicate the str was too short */
838 p
-= 2 - len
; /* overwrite last char */
839 p
+= snprintf(p
, 2, ">");
842 return (int)(p
- buf
);
845 /* print bytes formatted as hex to a string. return the resulting string length */
846 int bcm_format_hex(char *str
, const void *bytes
, int len
)
850 const u8
*src
= (const u8
*)bytes
;
852 for (i
= 0; i
< len
; i
++) {
853 p
+= snprintf(p
, 3, "%02X", *src
);
856 return (int)(p
- str
);
858 #endif /* defined(BCMDBG) */
860 /* pretty hex print a contiguous buffer */
861 void prhex(const char *msg
, unsigned char *buf
, uint nbytes
)
864 int len
= sizeof(line
);
868 if (msg
&& (msg
[0] != '\0'))
869 printf("%s:\n", msg
);
872 for (i
= 0; i
< nbytes
; i
++) {
874 nchar
= snprintf(p
, len
, " %04d: ", i
); /* line prefix */
879 nchar
= snprintf(p
, len
, "%02x ", buf
[i
]);
885 printf("%s\n", line
); /* flush line */
891 /* flush last partial line */
893 printf("%s\n", line
);
896 char *bcm_chipname(uint chipid
, char *buf
, uint len
)
900 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
901 snprintf(buf
, len
, fmt
, chipid
);
905 uint
bcm_mkiovar(char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
909 len
= strlen(name
) + 1;
911 if ((len
+ datalen
) > buflen
)
914 strncpy(buf
, name
, buflen
);
916 /* append data onto the end of the name string */
917 memcpy(&buf
[len
], data
, datalen
);
923 /* Quarter dBm units to mW
924 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
925 * Table is offset so the last entry is largest mW value that fits in
929 #define QDBM_OFFSET 153 /* Offset for first entry */
930 #define QDBM_TABLE_LEN 40 /* Table size */
932 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
933 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
935 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
937 /* Largest mW value that will round down to the last table entry,
938 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
939 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
940 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
942 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
944 static const u16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
945 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
946 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
947 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
948 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
949 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
950 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
953 u16
bcm_qdbm_to_mw(u8 qdbm
)
956 int idx
= qdbm
- QDBM_OFFSET
;
958 if (idx
>= QDBM_TABLE_LEN
) {
959 /* clamp to max u16 mW value */
963 /* scale the qdBm index up to the range of the table 0-40
964 * where an offset of 40 qdBm equals a factor of 10 mW.
971 /* return the mW value scaled down to the correct factor of 10,
972 * adding in factor/2 to get proper rounding.
974 return (nqdBm_to_mW_map
[idx
] + factor
/ 2) / factor
;
976 u8
bcm_mw_to_qdbm(u16 mw
)
983 /* handle boundary case */
987 offset
= QDBM_OFFSET
;
989 /* move mw into the range of the table */
990 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
995 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
- 1; qdbm
++) {
996 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+ 1] -
997 nqdBm_to_mW_map
[qdbm
]) / 2;
998 if (mw_uint
< boundary
)
1002 qdbm
+= (u8
) offset
;
1006 uint
bcm_bitcount(u8
*bitmap
, uint length
)
1008 uint bitcount
= 0, i
;
1010 for (i
= 0; i
< length
; i
++) {
1019 /* Initialization of bcmstrbuf structure */
1020 void bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
1022 b
->origsize
= b
->size
= size
;
1023 b
->origbuf
= b
->buf
= buf
;
1026 /* Buffer sprintf wrapper to guard against buffer overflow */
1027 int bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
1033 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
1035 /* Non Ansi C99 compliant returns -1,
1036 * Ansi compliant return r >= b->size,
1037 * bcmstdlib returns 0, handle all
1039 if ((r
== -1) || (r
>= (int)b
->size
) || (r
== 0)) {