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);
361 char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
363 snprintf(buf, 18, "%pM", ea->octet);
368 * Search the name=value vars for a specific one and return its value.
369 * Returns NULL if not found.
371 char *getvar(char *vars, const char *name)
383 /* first look in vars[] */
384 for (s = vars; s && *s;) {
385 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
394 /* then query nvram */
395 return nvram_get(name);
400 * Search the vars for a specific one and return its value as
401 * an integer. Returns 0 if not found.
403 int getintvar(char *vars, const char *name)
407 val = getvar(vars, name);
411 return simple_strtoul(val, NULL, 0);
415 /* pretty hex print a pkt buffer chain */
416 void prpkt(const char *msg, osl_t *osh, void *p0)
420 if (msg && (msg[0] != '\0'))
421 printf("%s:\n", msg);
423 for (p = p0; p; p = PKTNEXT(p))
424 prhex(NULL, PKTDATA(p), PKTLEN(p));
426 #endif /* defined(BCMDBG) */
428 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
429 * Also updates the inplace vlan tag if requested.
430 * For debugging, it returns an indication of what it did.
432 uint pktsetprio(void *pkt, bool update_vtag)
434 struct ether_header *eh;
435 struct ethervlan_header *evh;
440 pktdata = (u8 *) PKTDATA(pkt);
441 ASSERT(IS_ALIGNED((uintptr) pktdata, sizeof(u16)));
443 eh = (struct ether_header *)pktdata;
445 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
447 int vlan_prio, dscp_prio = 0;
449 evh = (struct ethervlan_header *)eh;
451 vlan_tag = ntoh16(evh->vlan_tag);
452 vlan_prio = (int)(vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
454 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
456 pktdata + sizeof(struct ethervlan_header);
457 u8 tos_tc = IP_TOS(ip_body);
458 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
461 /* DSCP priority gets precedence over 802.1P (vlan tag) */
462 if (dscp_prio != 0) {
463 priority = dscp_prio;
466 priority = vlan_prio;
470 * If the DSCP priority is not the same as the VLAN priority,
471 * then overwrite the priority field in the vlan tag, with the
472 * DSCP priority value. This is required for Linux APs because
473 * the VLAN driver on Linux, overwrites the skb->priority field
474 * with the priority value in the vlan tag
476 if (update_vtag && (priority != vlan_prio)) {
477 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
478 vlan_tag |= (u16) priority << VLAN_PRI_SHIFT;
479 evh->vlan_tag = hton16(vlan_tag);
482 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
483 u8 *ip_body = pktdata + sizeof(struct ether_header);
484 u8 tos_tc = IP_TOS(ip_body);
485 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
489 ASSERT(priority >= 0 && priority <= MAXPRIO);
490 PKTSETPRIO(pkt, priority);
491 return rc | priority;
494 static char bcm_undeferrstr[BCME_STRLEN];
496 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
498 /* Convert the error codes into related error strings */
499 const char *bcmerrorstr(int bcmerror)
501 /* check if someone added a bcmerror code but
502 forgot to add errorstring */
503 ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
505 if (bcmerror > 0 || bcmerror < BCME_LAST) {
506 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
508 return bcm_undeferrstr;
511 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
513 return bcmerrorstrtable[-bcmerror];
516 /* iovar table lookup */
517 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
519 const bcm_iovar_t *vi;
520 const char *lookup_name;
522 /* skip any ':' delimited option prefixes */
523 lookup_name = strrchr(name, ':');
524 if (lookup_name != NULL)
529 ASSERT(table != NULL);
531 for (vi = table; vi->name; vi++) {
532 if (!strcmp(vi->name, lookup_name))
535 /* ran to end of table */
537 return NULL; /* var name not found */
540 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
544 /* length check on io buf */
553 /* all integers are s32 sized args at the ioctl interface */
554 if (len < (int)sizeof(int)) {
555 bcmerror = BCME_BUFTOOSHORT;
560 /* buffer must meet minimum length requirement */
561 if (len < vi->minlen) {
562 bcmerror = BCME_BUFTOOSHORT;
568 /* Cannot return nil... */
569 bcmerror = BCME_UNSUPPORTED;
571 /* Set is an action w/o parameters */
572 bcmerror = BCME_BUFTOOLONG;
577 /* unknown type for length check in iovar info */
579 bcmerror = BCME_UNSUPPORTED;
585 /*******************************************************************************
588 * Computes a crc8 over the input data using the polynomial:
590 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
592 * The caller provides the initial value (either CRC8_INIT_VALUE
593 * or the previous returned value) to allow for processing of
594 * discontiguous blocks of data. When generating the CRC the
595 * caller is responsible for complementing the final return value
596 * and inserting it into the byte stream. When checking, a final
597 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
599 * Reference: Dallas Semiconductor Application Note 27
600 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
601 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
602 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
604 * ****************************************************************************
607 static const u8 crc8_table[256] = {
608 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
609 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
610 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
611 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
612 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
613 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
614 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
615 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
616 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
617 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
618 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
619 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
620 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
621 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
622 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
623 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
624 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
625 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
626 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
627 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
628 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
629 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
630 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
631 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
632 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
633 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
634 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
635 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
636 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
637 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
638 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
639 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
642 #define CRC_INNER_LOOP(n, c, x) \
643 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
645 u8 hndcrc8(u8 *pdata, /* pointer to array of data to process */
646 uint nbytes, /* number of input data bytes to process */
647 u8 crc /* either CRC8_INIT_VALUE or previous return value */
649 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
650 * to avoid the undefined and unnecessary (u8 >> 8) operation.
653 crc = crc8_table[(crc ^ *pdata++) & 0xff];
658 /*******************************************************************************
661 * Computes a crc16 over the input data using the polynomial:
663 * x^16 + x^12 +x^5 + 1
665 * The caller provides the initial value (either CRC16_INIT_VALUE
666 * or the previous returned value) to allow for processing of
667 * discontiguous blocks of data. When generating the CRC the
668 * caller is responsible for complementing the final return value
669 * and inserting it into the byte stream. When checking, a final
670 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
672 * Reference: Dallas Semiconductor Application Note 27
673 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
674 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
675 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
677 * ****************************************************************************
680 static const u16 crc16_table[256] = {
681 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
682 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
683 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
684 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
685 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
686 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
687 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
688 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
689 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
690 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
691 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
692 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
693 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
694 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
695 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
696 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
697 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
698 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
699 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
700 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
701 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
702 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
703 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
704 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
705 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
706 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
707 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
708 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
709 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
710 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
711 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
712 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
715 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
716 uint nbytes, /* number of input data bytes to process */
717 u16 crc /* either CRC16_INIT_VALUE or previous return value */
720 CRC_INNER_LOOP(16, crc, *pdata++);
724 static const u32 crc32_table[256] = {
725 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
726 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
727 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
728 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
729 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
730 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
731 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
732 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
733 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
734 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
735 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
736 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
737 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
738 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
739 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
740 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
741 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
742 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
743 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
744 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
745 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
746 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
747 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
748 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
749 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
750 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
751 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
752 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
753 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
754 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
755 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
756 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
757 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
758 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
759 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
760 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
761 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
762 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
763 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
764 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
765 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
766 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
767 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
768 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
769 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
770 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
771 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
772 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
773 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
774 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
775 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
776 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
777 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
778 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
779 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
780 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
781 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
782 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
783 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
784 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
785 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
786 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
787 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
788 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
791 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
792 uint nbytes, /* number of input data bytes to process */
793 u32 crc /* either CRC32_INIT_VALUE or previous
800 unsigned long *tptr = (unsigned long *) tmp;
802 /* in case the beginning of the buffer isn't aligned */
803 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
804 nbytes -= (pend - pdata);
806 CRC_INNER_LOOP(32, crc, *pdata++);
808 /* handle bulk of data as 32-bit words */
809 pend = pdata + (nbytes & 0xfffffffc);
810 while (pdata < pend) {
811 *tptr = *(unsigned long *) pdata;
812 pdata += sizeof(unsigned long *);
813 CRC_INNER_LOOP(32, crc, tmp[0]);
814 CRC_INNER_LOOP(32, crc, tmp[1]);
815 CRC_INNER_LOOP(32, crc, tmp[2]);
816 CRC_INNER_LOOP(32, crc, tmp[3]);
819 /* 1-3 bytes at end of buffer */
820 pend = pdata + (nbytes & 0x03);
822 CRC_INNER_LOOP(32, crc, *pdata++);
824 pend = pdata + nbytes;
826 CRC_INNER_LOOP(32, crc, *pdata++);
827 #endif /* __mips__ */
832 * Traverse a string of 1-byte tag/1-byte length/variable-length value
833 * triples, returning a pointer to the substring whose first element
836 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
841 elt = (bcm_tlv_t *) buf;
844 /* find tagged parameter */
845 while (totlen >= 2) {
848 /* validate remaining totlen */
849 if ((elt->id == key) && (totlen >= (len + 2)))
852 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
862 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
867 int slen = 0, nlen = 0;
876 for (i = 0; flags != 0; i++) {
879 if (bit == 0 && flags != 0) {
880 /* print any unnamed bits */
881 snprintf(hexstr, 16, "0x%X", flags);
883 flags = 0; /* exit loop */
884 } else if ((flags & bit) == 0)
889 /* count btwn flag space */
892 /* need NULL char as well */
895 /* copy NULL char but don't count it */
896 strncpy(p, name, nlen + 1);
898 /* copy btwn flag space and NULL char */
900 p += snprintf(p, 2, " ");
904 /* indicate the str was too short */
907 p -= 2 - len; /* overwrite last char */
908 p += snprintf(p, 2, ">");
911 return (int)(p - buf);
914 /* print bytes formatted as hex to a string. return the resulting string length */
915 int bcm_format_hex(char *str, const void *bytes, int len)
919 const u8 *src = (const u8 *)bytes;
921 for (i = 0; i < len; i++) {
922 p += snprintf(p, 3, "%02X", *src);
925 return (int)(p - str);
927 #endif /* defined(BCMDBG) */
929 /* pretty hex print a contiguous buffer */
930 void prhex(const char *msg, unsigned char *buf, uint nbytes)
933 int len = sizeof(line);
937 if (msg && (msg[0] != '\0'))
938 printf("%s:\n", msg);
941 for (i = 0; i < nbytes; i++) {
943 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
948 nchar = snprintf(p, len, "%02x ", buf[i]);
954 printf("%s\n", line); /* flush line */
960 /* flush last partial line */
962 printf("%s\n", line);
965 char *bcm_chipname(uint chipid, char *buf, uint len)
969 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
970 snprintf(buf, len, fmt, chipid);
974 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
978 len = strlen(name) + 1;
980 if ((len + datalen) > buflen)
983 strncpy(buf, name, buflen);
985 /* append data onto the end of the name string */
986 memcpy(&buf[len], data, datalen);
992 /* Quarter dBm units to mW
993 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
994 * Table is offset so the last entry is largest mW value that fits in
998 #define QDBM_OFFSET 153 /* Offset for first entry */
999 #define QDBM_TABLE_LEN 40 /* Table size */
1001 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1002 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1004 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1006 /* Largest mW value that will round down to the last table entry,
1007 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1008 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
1009 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1011 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1013 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1014 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1015 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1016 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1017 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1018 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1019 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1022 u16 bcm_qdbm_to_mw(u8 qdbm)
1025 int idx = qdbm - QDBM_OFFSET;
1027 if (idx >= QDBM_TABLE_LEN) {
1028 /* clamp to max u16 mW value */
1032 /* scale the qdBm index up to the range of the table 0-40
1033 * where an offset of 40 qdBm equals a factor of 10 mW.
1040 /* return the mW value scaled down to the correct factor of 10,
1041 * adding in factor/2 to get proper rounding.
1043 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
1045 u8 bcm_mw_to_qdbm(u16 mw)
1052 /* handle boundary case */
1056 offset = QDBM_OFFSET;
1058 /* move mw into the range of the table */
1059 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1064 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1065 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1066 nqdBm_to_mW_map[qdbm]) / 2;
1067 if (mw_uint < boundary)
1071 qdbm += (u8) offset;
1075 uint bcm_bitcount(u8 *bitmap, uint length)
1077 uint bitcount = 0, i;
1079 for (i = 0; i < length; i++) {
1088 /* Initialization of bcmstrbuf structure */
1089 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1091 b->origsize = b->size = size;
1092 b->origbuf = b->buf = buf;
1095 /* Buffer sprintf wrapper to guard against buffer overflow */
1096 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1102 r = vsnprintf(b->buf, b->size, fmt, ap);
1104 /* Non Ansi C99 compliant returns -1,
1105 * Ansi compliant return r >= b->size,
1106 * bcmstdlib returns 0, handle all
1108 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {