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 */
218 pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir,
219 ifpkt_cb_t fn, int arg)
222 struct sk_buff *p, *prev = NULL;
227 if (fn == NULL || (*fn) (p, arg)) {
228 bool head = (p == q->head);
232 prev->prev = p->prev;
234 pkt_buf_free_skb(osh, p, dir);
237 p = (head ? q->head : prev->prev);
244 if (q->head == NULL) {
250 void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir,
251 ifpkt_cb_t fn, int arg)
254 for (prec = 0; prec < pq->num_prec; prec++)
255 pktq_pflush(osh, pq, prec, dir, fn, arg);
257 ASSERT(pq->len == 0);
259 #endif /* BRCM_FULLMAC */
261 void pktq_init(struct pktq *pq, int num_prec, int max_len)
265 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
267 /* pq is variable size; only zero out what's requested */
269 offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
271 pq->num_prec = (u16) num_prec;
273 pq->max = (u16) max_len;
275 for (prec = 0; prec < num_prec; prec++)
276 pq->q[prec].max = pq->max;
279 struct sk_buff *pktq_peek_tail(struct pktq *pq, int *prec_out)
286 for (prec = 0; prec < pq->hi_prec; prec++)
287 if (pq->q[prec].head)
293 return pq->q[prec].tail;
296 /* Return sum of lengths of a specific set of precedences */
297 int pktq_mlen(struct pktq *pq, uint prec_bmp)
303 for (prec = 0; prec <= pq->hi_prec; prec++)
304 if (prec_bmp & (1 << prec))
305 len += pq->q[prec].len;
309 /* Priority dequeue from a specific set of precedences */
310 struct sk_buff *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp,
320 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
323 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
349 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
350 int bcm_ether_atoe(char *p, u8 *ea)
355 ea[i++] = (char)simple_strtoul(p, &p, 16);
364 * Search the name=value vars for a specific one and return its value.
365 * Returns NULL if not found.
367 char *getvar(char *vars, const char *name)
379 /* first look in vars[] */
380 for (s = vars; s && *s;) {
381 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
390 /* then query nvram */
391 return nvram_get(name);
396 * Search the vars for a specific one and return its value as
397 * an integer. Returns 0 if not found.
399 int getintvar(char *vars, const char *name)
403 val = getvar(vars, name);
407 return simple_strtoul(val, NULL, 0);
411 /* pretty hex print a pkt buffer chain */
412 void prpkt(const char *msg, struct osl_info *osh, struct sk_buff *p0)
416 if (msg && (msg[0] != '\0'))
417 printf("%s:\n", msg);
419 for (p = p0; p; p = p->next)
420 prhex(NULL, p->data, p->len);
422 #endif /* defined(BCMDBG) */
424 static char bcm_undeferrstr[BCME_STRLEN];
426 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
428 /* Convert the error codes into related error strings */
429 const char *bcmerrorstr(int bcmerror)
431 /* check if someone added a bcmerror code but
432 forgot to add errorstring */
433 ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
435 if (bcmerror > 0 || bcmerror < BCME_LAST) {
436 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
438 return bcm_undeferrstr;
441 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
443 return bcmerrorstrtable[-bcmerror];
446 /* iovar table lookup */
447 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
449 const bcm_iovar_t *vi;
450 const char *lookup_name;
452 /* skip any ':' delimited option prefixes */
453 lookup_name = strrchr(name, ':');
454 if (lookup_name != NULL)
459 ASSERT(table != NULL);
461 for (vi = table; vi->name; vi++) {
462 if (!strcmp(vi->name, lookup_name))
465 /* ran to end of table */
467 return NULL; /* var name not found */
470 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
474 /* length check on io buf */
483 /* all integers are s32 sized args at the ioctl interface */
484 if (len < (int)sizeof(int)) {
485 bcmerror = BCME_BUFTOOSHORT;
490 /* buffer must meet minimum length requirement */
491 if (len < vi->minlen) {
492 bcmerror = BCME_BUFTOOSHORT;
498 /* Cannot return nil... */
499 bcmerror = BCME_UNSUPPORTED;
501 /* Set is an action w/o parameters */
502 bcmerror = BCME_BUFTOOLONG;
507 /* unknown type for length check in iovar info */
509 bcmerror = BCME_UNSUPPORTED;
515 /*******************************************************************************
518 * Computes a crc8 over the input data using the polynomial:
520 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
522 * The caller provides the initial value (either CRC8_INIT_VALUE
523 * or the previous returned value) to allow for processing of
524 * discontiguous blocks of data. When generating the CRC the
525 * caller is responsible for complementing the final return value
526 * and inserting it into the byte stream. When checking, a final
527 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
529 * Reference: Dallas Semiconductor Application Note 27
530 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
531 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
532 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
534 * ****************************************************************************
537 static const u8 crc8_table[256] = {
538 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
539 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
540 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
541 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
542 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
543 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
544 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
545 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
546 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
547 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
548 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
549 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
550 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
551 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
552 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
553 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
554 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
555 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
556 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
557 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
558 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
559 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
560 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
561 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
562 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
563 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
564 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
565 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
566 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
567 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
568 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
569 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
572 #define CRC_INNER_LOOP(n, c, x) \
573 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
575 u8 hndcrc8(u8 *pdata, /* pointer to array of data to process */
576 uint nbytes, /* number of input data bytes to process */
577 u8 crc /* either CRC8_INIT_VALUE or previous return value */
579 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
580 * to avoid the undefined and unnecessary (u8 >> 8) operation.
583 crc = crc8_table[(crc ^ *pdata++) & 0xff];
588 /*******************************************************************************
591 * Computes a crc16 over the input data using the polynomial:
593 * x^16 + x^12 +x^5 + 1
595 * The caller provides the initial value (either CRC16_INIT_VALUE
596 * or the previous returned value) to allow for processing of
597 * discontiguous blocks of data. When generating the CRC the
598 * caller is responsible for complementing the final return value
599 * and inserting it into the byte stream. When checking, a final
600 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
602 * Reference: Dallas Semiconductor Application Note 27
603 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
604 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
605 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
607 * ****************************************************************************
610 static const u16 crc16_table[256] = {
611 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
612 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
613 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
614 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
615 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
616 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
617 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
618 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
619 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
620 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
621 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
622 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
623 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
624 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
625 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
626 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
627 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
628 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
629 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
630 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
631 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
632 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
633 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
634 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
635 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
636 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
637 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
638 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
639 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
640 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
641 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
642 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
645 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
646 uint nbytes, /* number of input data bytes to process */
647 u16 crc /* either CRC16_INIT_VALUE or previous return value */
650 CRC_INNER_LOOP(16, crc, *pdata++);
654 static const u32 crc32_table[256] = {
655 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
656 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
657 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
658 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
659 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
660 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
661 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
662 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
663 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
664 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
665 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
666 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
667 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
668 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
669 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
670 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
671 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
672 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
673 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
674 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
675 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
676 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
677 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
678 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
679 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
680 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
681 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
682 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
683 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
684 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
685 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
686 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
687 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
688 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
689 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
690 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
691 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
692 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
693 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
694 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
695 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
696 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
697 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
698 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
699 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
700 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
701 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
702 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
703 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
704 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
705 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
706 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
707 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
708 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
709 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
710 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
711 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
712 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
713 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
714 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
715 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
716 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
717 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
718 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
721 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
722 uint nbytes, /* number of input data bytes to process */
723 u32 crc /* either CRC32_INIT_VALUE or previous
730 unsigned long *tptr = (unsigned long *) tmp;
732 /* in case the beginning of the buffer isn't aligned */
733 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
734 nbytes -= (pend - pdata);
736 CRC_INNER_LOOP(32, crc, *pdata++);
738 /* handle bulk of data as 32-bit words */
739 pend = pdata + (nbytes & 0xfffffffc);
740 while (pdata < pend) {
741 *tptr = *(unsigned long *) pdata;
742 pdata += sizeof(unsigned long *);
743 CRC_INNER_LOOP(32, crc, tmp[0]);
744 CRC_INNER_LOOP(32, crc, tmp[1]);
745 CRC_INNER_LOOP(32, crc, tmp[2]);
746 CRC_INNER_LOOP(32, crc, tmp[3]);
749 /* 1-3 bytes at end of buffer */
750 pend = pdata + (nbytes & 0x03);
752 CRC_INNER_LOOP(32, crc, *pdata++);
754 pend = pdata + nbytes;
756 CRC_INNER_LOOP(32, crc, *pdata++);
757 #endif /* __mips__ */
762 * Traverse a string of 1-byte tag/1-byte length/variable-length value
763 * triples, returning a pointer to the substring whose first element
766 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
771 elt = (bcm_tlv_t *) buf;
774 /* find tagged parameter */
775 while (totlen >= 2) {
778 /* validate remaining totlen */
779 if ((elt->id == key) && (totlen >= (len + 2)))
782 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
792 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
797 int slen = 0, nlen = 0;
806 for (i = 0; flags != 0; i++) {
809 if (bit == 0 && flags != 0) {
810 /* print any unnamed bits */
811 snprintf(hexstr, 16, "0x%X", flags);
813 flags = 0; /* exit loop */
814 } else if ((flags & bit) == 0)
819 /* count btwn flag space */
822 /* need NULL char as well */
825 /* copy NULL char but don't count it */
826 strncpy(p, name, nlen + 1);
828 /* copy btwn flag space and NULL char */
830 p += snprintf(p, 2, " ");
834 /* indicate the str was too short */
837 p -= 2 - len; /* overwrite last char */
838 p += snprintf(p, 2, ">");
841 return (int)(p - buf);
844 /* print bytes formatted as hex to a string. return the resulting string length */
845 int bcm_format_hex(char *str, const void *bytes, int len)
849 const u8 *src = (const u8 *)bytes;
851 for (i = 0; i < len; i++) {
852 p += snprintf(p, 3, "%02X", *src);
855 return (int)(p - str);
857 #endif /* defined(BCMDBG) */
859 /* pretty hex print a contiguous buffer */
860 void prhex(const char *msg, unsigned char *buf, uint nbytes)
863 int len = sizeof(line);
867 if (msg && (msg[0] != '\0'))
868 printf("%s:\n", msg);
871 for (i = 0; i < nbytes; i++) {
873 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
878 nchar = snprintf(p, len, "%02x ", buf[i]);
884 printf("%s\n", line); /* flush line */
890 /* flush last partial line */
892 printf("%s\n", line);
895 char *bcm_chipname(uint chipid, char *buf, uint len)
899 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
900 snprintf(buf, len, fmt, chipid);
904 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
908 len = strlen(name) + 1;
910 if ((len + datalen) > buflen)
913 strncpy(buf, name, buflen);
915 /* append data onto the end of the name string */
916 memcpy(&buf[len], data, datalen);
922 /* Quarter dBm units to mW
923 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
924 * Table is offset so the last entry is largest mW value that fits in
928 #define QDBM_OFFSET 153 /* Offset for first entry */
929 #define QDBM_TABLE_LEN 40 /* Table size */
931 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
932 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
934 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
936 /* Largest mW value that will round down to the last table entry,
937 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
938 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
939 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
941 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
943 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
944 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
945 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
946 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
947 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
948 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
949 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
952 u16 bcm_qdbm_to_mw(u8 qdbm)
955 int idx = qdbm - QDBM_OFFSET;
957 if (idx >= QDBM_TABLE_LEN) {
958 /* clamp to max u16 mW value */
962 /* scale the qdBm index up to the range of the table 0-40
963 * where an offset of 40 qdBm equals a factor of 10 mW.
970 /* return the mW value scaled down to the correct factor of 10,
971 * adding in factor/2 to get proper rounding.
973 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
975 u8 bcm_mw_to_qdbm(u16 mw)
982 /* handle boundary case */
986 offset = QDBM_OFFSET;
988 /* move mw into the range of the table */
989 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
994 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
995 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
996 nqdBm_to_mW_map[qdbm]) / 2;
997 if (mw_uint < boundary)
1001 qdbm += (u8) offset;
1005 uint bcm_bitcount(u8 *bitmap, uint length)
1007 uint bitcount = 0, i;
1009 for (i = 0; i < length; i++) {
1018 /* Initialization of bcmstrbuf structure */
1019 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1021 b->origsize = b->size = size;
1022 b->origbuf = b->buf = buf;
1025 /* Buffer sprintf wrapper to guard against buffer overflow */
1026 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1032 r = vsnprintf(b->buf, b->size, fmt, ap);
1034 /* Non Ansi C99 compliant returns -1,
1035 * Ansi compliant return r >= b->size,
1036 * bcmstdlib returns 0, handle all
1038 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {