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.
21 #include <linux/ctype.h>
22 #include <linux/kernel.h>
23 #include <linux/string.h>
28 #include <bcmendian.h>
30 #include <proto/ethernet.h>
31 #include <proto/vlan.h>
32 #include <proto/bcmip.h>
33 #include <proto/802.1d.h>
34 #include <proto/802.11.h>
37 /* copy a buffer into a pkt buffer chain */
38 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf)
42 /* skip 'offset' bytes */
43 for (; p && offset; p = PKTNEXT(p)) {
44 if (offset < (uint) PKTLEN(p))
53 for (; p && len; p = PKTNEXT(p)) {
54 n = min((uint) PKTLEN(p) - offset, (uint) len);
55 bcopy(buf, PKTDATA(p) + offset, n);
64 /* return total length of buffer chain */
65 uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
70 for (; p; p = PKTNEXT(p))
76 * osl multiple-precedence packet queue
77 * hi_prec is always >= the number of the highest non-empty precedence
79 void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
83 ASSERT(prec >= 0 && prec < pq->num_prec);
84 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
86 ASSERT(!pktq_full(pq));
87 ASSERT(!pktq_pfull(pq, prec));
92 PKTSETLINK(q->tail, p);
101 if (pq->hi_prec < prec)
102 pq->hi_prec = (u8) prec;
107 void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p)
111 ASSERT(prec >= 0 && prec < pq->num_prec);
112 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
114 ASSERT(!pktq_full(pq));
115 ASSERT(!pktq_pfull(pq, prec));
122 PKTSETLINK(p, q->head);
128 if (pq->hi_prec < prec)
129 pq->hi_prec = (u8) prec;
134 void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
139 ASSERT(prec >= 0 && prec < pq->num_prec);
147 q->head = PKTLINK(p);
160 void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
165 ASSERT(prec >= 0 && prec < pq->num_prec);
173 for (prev = NULL; p != q->tail; p = PKTLINK(p))
177 PKTSETLINK(prev, NULL);
190 void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
198 q->head = PKTLINK(p);
200 PKTFREE(osh, p, dir);
209 void pktq_flush(osl_t *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(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
222 void *p, *prev = NULL;
227 if (fn == NULL || (*fn) (p, arg)) {
228 bool head = (p == q->head);
230 q->head = PKTLINK(p);
232 PKTSETLINK(prev, PKTLINK(p));
234 PKTFREE(osh, p, dir);
237 p = (head ? q->head : PKTLINK(prev));
244 if (q->head == NULL) {
250 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
253 for (prec = 0; prec < pq->num_prec; prec++)
254 pktq_pflush(osh, pq, prec, dir, fn, arg);
256 ASSERT(pq->len == 0);
258 #endif /* BRCM_FULLMAC */
260 void pktq_init(struct pktq *pq, int num_prec, int max_len)
264 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
266 /* pq is variable size; only zero out what's requested */
268 offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
270 pq->num_prec = (u16) num_prec;
272 pq->max = (u16) max_len;
274 for (prec = 0; prec < num_prec; prec++)
275 pq->q[prec].max = pq->max;
278 void *pktq_peek_tail(struct pktq *pq, int *prec_out)
285 for (prec = 0; prec < pq->hi_prec; prec++)
286 if (pq->q[prec].head)
292 return pq->q[prec].tail;
295 /* Return sum of lengths of a specific set of precedences */
296 int pktq_mlen(struct pktq *pq, uint prec_bmp)
302 for (prec = 0; prec <= pq->hi_prec; prec++)
303 if (prec_bmp & (1 << prec))
304 len += pq->q[prec].len;
308 /* Priority dequeue from a specific set of precedences */
309 void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
318 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
321 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
331 q->head = PKTLINK(p);
347 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
348 int bcm_ether_atoe(char *p, struct ether_addr *ea)
353 ea->octet[i++] = (char)simple_strtoul(p, &p, 16);
362 * Search the name=value vars for a specific one and return its value.
363 * Returns NULL if not found.
365 char *getvar(char *vars, const char *name)
377 /* first look in vars[] */
378 for (s = vars; s && *s;) {
379 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
388 /* then query nvram */
389 return nvram_get(name);
394 * Search the vars for a specific one and return its value as
395 * an integer. Returns 0 if not found.
397 int getintvar(char *vars, const char *name)
401 val = getvar(vars, name);
405 return simple_strtoul(val, NULL, 0);
409 /* pretty hex print a pkt buffer chain */
410 void prpkt(const char *msg, osl_t *osh, void *p0)
414 if (msg && (msg[0] != '\0'))
415 printf("%s:\n", msg);
417 for (p = p0; p; p = PKTNEXT(p))
418 prhex(NULL, PKTDATA(p), PKTLEN(p));
420 #endif /* defined(BCMDBG) */
422 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
423 * Also updates the inplace vlan tag if requested.
424 * For debugging, it returns an indication of what it did.
426 uint pktsetprio(void *pkt, bool update_vtag)
428 struct ether_header *eh;
429 struct ethervlan_header *evh;
434 pktdata = (u8 *) PKTDATA(pkt);
435 ASSERT(IS_ALIGNED((unsigned long)pktdata, sizeof(u16)));
437 eh = (struct ether_header *)pktdata;
439 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
441 int vlan_prio, dscp_prio = 0;
443 evh = (struct ethervlan_header *)eh;
445 vlan_tag = ntoh16(evh->vlan_tag);
446 vlan_prio = (int)(vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
448 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
450 pktdata + sizeof(struct ethervlan_header);
451 u8 tos_tc = IP_TOS(ip_body);
452 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
455 /* DSCP priority gets precedence over 802.1P (vlan tag) */
456 if (dscp_prio != 0) {
457 priority = dscp_prio;
460 priority = vlan_prio;
464 * If the DSCP priority is not the same as the VLAN priority,
465 * then overwrite the priority field in the vlan tag, with the
466 * DSCP priority value. This is required for Linux APs because
467 * the VLAN driver on Linux, overwrites the skb->priority field
468 * with the priority value in the vlan tag
470 if (update_vtag && (priority != vlan_prio)) {
471 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
472 vlan_tag |= (u16) priority << VLAN_PRI_SHIFT;
473 evh->vlan_tag = hton16(vlan_tag);
476 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
477 u8 *ip_body = pktdata + sizeof(struct ether_header);
478 u8 tos_tc = IP_TOS(ip_body);
479 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
483 ASSERT(priority >= 0 && priority <= MAXPRIO);
484 PKTSETPRIO(pkt, priority);
485 return rc | priority;
488 static char bcm_undeferrstr[BCME_STRLEN];
490 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
492 /* Convert the error codes into related error strings */
493 const char *bcmerrorstr(int bcmerror)
495 /* check if someone added a bcmerror code but
496 forgot to add errorstring */
497 ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
499 if (bcmerror > 0 || bcmerror < BCME_LAST) {
500 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
502 return bcm_undeferrstr;
505 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
507 return bcmerrorstrtable[-bcmerror];
510 /* iovar table lookup */
511 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
513 const bcm_iovar_t *vi;
514 const char *lookup_name;
516 /* skip any ':' delimited option prefixes */
517 lookup_name = strrchr(name, ':');
518 if (lookup_name != NULL)
523 ASSERT(table != NULL);
525 for (vi = table; vi->name; vi++) {
526 if (!strcmp(vi->name, lookup_name))
529 /* ran to end of table */
531 return NULL; /* var name not found */
534 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
538 /* length check on io buf */
547 /* all integers are s32 sized args at the ioctl interface */
548 if (len < (int)sizeof(int)) {
549 bcmerror = BCME_BUFTOOSHORT;
554 /* buffer must meet minimum length requirement */
555 if (len < vi->minlen) {
556 bcmerror = BCME_BUFTOOSHORT;
562 /* Cannot return nil... */
563 bcmerror = BCME_UNSUPPORTED;
565 /* Set is an action w/o parameters */
566 bcmerror = BCME_BUFTOOLONG;
571 /* unknown type for length check in iovar info */
573 bcmerror = BCME_UNSUPPORTED;
579 /*******************************************************************************
582 * Computes a crc8 over the input data using the polynomial:
584 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
586 * The caller provides the initial value (either CRC8_INIT_VALUE
587 * or the previous returned value) to allow for processing of
588 * discontiguous blocks of data. When generating the CRC the
589 * caller is responsible for complementing the final return value
590 * and inserting it into the byte stream. When checking, a final
591 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
593 * Reference: Dallas Semiconductor Application Note 27
594 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
595 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
596 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
598 * ****************************************************************************
601 static const u8 crc8_table[256] = {
602 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
603 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
604 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
605 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
606 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
607 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
608 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
609 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
610 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
611 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
612 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
613 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
614 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
615 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
616 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
617 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
618 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
619 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
620 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
621 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
622 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
623 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
624 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
625 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
626 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
627 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
628 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
629 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
630 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
631 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
632 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
633 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
636 #define CRC_INNER_LOOP(n, c, x) \
637 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
639 u8 hndcrc8(u8 *pdata, /* pointer to array of data to process */
640 uint nbytes, /* number of input data bytes to process */
641 u8 crc /* either CRC8_INIT_VALUE or previous return value */
643 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
644 * to avoid the undefined and unnecessary (u8 >> 8) operation.
647 crc = crc8_table[(crc ^ *pdata++) & 0xff];
652 /*******************************************************************************
655 * Computes a crc16 over the input data using the polynomial:
657 * x^16 + x^12 +x^5 + 1
659 * The caller provides the initial value (either CRC16_INIT_VALUE
660 * or the previous returned value) to allow for processing of
661 * discontiguous blocks of data. When generating the CRC the
662 * caller is responsible for complementing the final return value
663 * and inserting it into the byte stream. When checking, a final
664 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
666 * Reference: Dallas Semiconductor Application Note 27
667 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
668 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
669 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
671 * ****************************************************************************
674 static const u16 crc16_table[256] = {
675 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
676 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
677 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
678 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
679 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
680 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
681 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
682 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
683 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
684 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
685 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
686 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
687 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
688 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
689 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
690 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
691 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
692 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
693 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
694 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
695 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
696 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
697 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
698 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
699 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
700 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
701 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
702 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
703 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
704 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
705 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
706 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
709 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
710 uint nbytes, /* number of input data bytes to process */
711 u16 crc /* either CRC16_INIT_VALUE or previous return value */
714 CRC_INNER_LOOP(16, crc, *pdata++);
718 static const u32 crc32_table[256] = {
719 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
720 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
721 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
722 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
723 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
724 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
725 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
726 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
727 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
728 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
729 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
730 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
731 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
732 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
733 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
734 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
735 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
736 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
737 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
738 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
739 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
740 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
741 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
742 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
743 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
744 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
745 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
746 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
747 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
748 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
749 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
750 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
751 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
752 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
753 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
754 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
755 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
756 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
757 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
758 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
759 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
760 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
761 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
762 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
763 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
764 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
765 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
766 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
767 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
768 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
769 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
770 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
771 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
772 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
773 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
774 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
775 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
776 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
777 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
778 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
779 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
780 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
781 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
782 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
785 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
786 uint nbytes, /* number of input data bytes to process */
787 u32 crc /* either CRC32_INIT_VALUE or previous
794 unsigned long *tptr = (unsigned long *) tmp;
796 /* in case the beginning of the buffer isn't aligned */
797 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
798 nbytes -= (pend - pdata);
800 CRC_INNER_LOOP(32, crc, *pdata++);
802 /* handle bulk of data as 32-bit words */
803 pend = pdata + (nbytes & 0xfffffffc);
804 while (pdata < pend) {
805 *tptr = *(unsigned long *) pdata;
806 pdata += sizeof(unsigned long *);
807 CRC_INNER_LOOP(32, crc, tmp[0]);
808 CRC_INNER_LOOP(32, crc, tmp[1]);
809 CRC_INNER_LOOP(32, crc, tmp[2]);
810 CRC_INNER_LOOP(32, crc, tmp[3]);
813 /* 1-3 bytes at end of buffer */
814 pend = pdata + (nbytes & 0x03);
816 CRC_INNER_LOOP(32, crc, *pdata++);
818 pend = pdata + nbytes;
820 CRC_INNER_LOOP(32, crc, *pdata++);
821 #endif /* __mips__ */
826 * Traverse a string of 1-byte tag/1-byte length/variable-length value
827 * triples, returning a pointer to the substring whose first element
830 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
835 elt = (bcm_tlv_t *) buf;
838 /* find tagged parameter */
839 while (totlen >= 2) {
842 /* validate remaining totlen */
843 if ((elt->id == key) && (totlen >= (len + 2)))
846 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
856 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
861 int slen = 0, nlen = 0;
870 for (i = 0; flags != 0; i++) {
873 if (bit == 0 && flags != 0) {
874 /* print any unnamed bits */
875 snprintf(hexstr, 16, "0x%X", flags);
877 flags = 0; /* exit loop */
878 } else if ((flags & bit) == 0)
883 /* count btwn flag space */
886 /* need NULL char as well */
889 /* copy NULL char but don't count it */
890 strncpy(p, name, nlen + 1);
892 /* copy btwn flag space and NULL char */
894 p += snprintf(p, 2, " ");
898 /* indicate the str was too short */
901 p -= 2 - len; /* overwrite last char */
902 p += snprintf(p, 2, ">");
905 return (int)(p - buf);
908 /* print bytes formatted as hex to a string. return the resulting string length */
909 int bcm_format_hex(char *str, const void *bytes, int len)
913 const u8 *src = (const u8 *)bytes;
915 for (i = 0; i < len; i++) {
916 p += snprintf(p, 3, "%02X", *src);
919 return (int)(p - str);
921 #endif /* defined(BCMDBG) */
923 /* pretty hex print a contiguous buffer */
924 void prhex(const char *msg, unsigned char *buf, uint nbytes)
927 int len = sizeof(line);
931 if (msg && (msg[0] != '\0'))
932 printf("%s:\n", msg);
935 for (i = 0; i < nbytes; i++) {
937 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
942 nchar = snprintf(p, len, "%02x ", buf[i]);
948 printf("%s\n", line); /* flush line */
954 /* flush last partial line */
956 printf("%s\n", line);
959 char *bcm_chipname(uint chipid, char *buf, uint len)
963 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
964 snprintf(buf, len, fmt, chipid);
968 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
972 len = strlen(name) + 1;
974 if ((len + datalen) > buflen)
977 strncpy(buf, name, buflen);
979 /* append data onto the end of the name string */
980 memcpy(&buf[len], data, datalen);
986 /* Quarter dBm units to mW
987 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
988 * Table is offset so the last entry is largest mW value that fits in
992 #define QDBM_OFFSET 153 /* Offset for first entry */
993 #define QDBM_TABLE_LEN 40 /* Table size */
995 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
996 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
998 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1000 /* Largest mW value that will round down to the last table entry,
1001 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1002 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
1003 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1005 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1007 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1008 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1009 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1010 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1011 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1012 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1013 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1016 u16 bcm_qdbm_to_mw(u8 qdbm)
1019 int idx = qdbm - QDBM_OFFSET;
1021 if (idx >= QDBM_TABLE_LEN) {
1022 /* clamp to max u16 mW value */
1026 /* scale the qdBm index up to the range of the table 0-40
1027 * where an offset of 40 qdBm equals a factor of 10 mW.
1034 /* return the mW value scaled down to the correct factor of 10,
1035 * adding in factor/2 to get proper rounding.
1037 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
1039 u8 bcm_mw_to_qdbm(u16 mw)
1046 /* handle boundary case */
1050 offset = QDBM_OFFSET;
1052 /* move mw into the range of the table */
1053 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1058 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1059 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1060 nqdBm_to_mW_map[qdbm]) / 2;
1061 if (mw_uint < boundary)
1065 qdbm += (u8) offset;
1069 uint bcm_bitcount(u8 *bitmap, uint length)
1071 uint bitcount = 0, i;
1073 for (i = 0; i < length; i++) {
1082 /* Initialization of bcmstrbuf structure */
1083 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1085 b->origsize = b->size = size;
1086 b->origbuf = b->buf = buf;
1089 /* Buffer sprintf wrapper to guard against buffer overflow */
1090 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1096 r = vsnprintf(b->buf, b->size, fmt, ap);
1098 /* Non Ansi C99 compliant returns -1,
1099 * Ansi compliant return r >= b->size,
1100 * bcmstdlib returns 0, handle all
1102 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {