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>
27 #include <bcmendian.h>
29 #include <proto/ethernet.h>
30 #include <proto/vlan.h>
31 #include <proto/bcmip.h>
32 #include <proto/802.1d.h>
33 #include <proto/802.11.h>
36 /* copy a buffer into a pkt buffer chain */
37 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf)
41 /* skip 'offset' bytes */
42 for (; p && offset; p = PKTNEXT(p)) {
43 if (offset < (uint) PKTLEN(p))
52 for (; p && len; p = PKTNEXT(p)) {
53 n = min((uint) PKTLEN(p) - offset, (uint) len);
54 bcopy(buf, PKTDATA(p) + offset, n);
63 /* return total length of buffer chain */
64 uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
69 for (; p; p = PKTNEXT(p))
75 * osl multiple-precedence packet queue
76 * hi_prec is always >= the number of the highest non-empty precedence
78 void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
82 ASSERT(prec >= 0 && prec < pq->num_prec);
83 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
85 ASSERT(!pktq_full(pq));
86 ASSERT(!pktq_pfull(pq, prec));
91 PKTSETLINK(q->tail, p);
100 if (pq->hi_prec < prec)
101 pq->hi_prec = (u8) prec;
106 void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p)
110 ASSERT(prec >= 0 && prec < pq->num_prec);
111 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
113 ASSERT(!pktq_full(pq));
114 ASSERT(!pktq_pfull(pq, prec));
121 PKTSETLINK(p, q->head);
127 if (pq->hi_prec < prec)
128 pq->hi_prec = (u8) prec;
133 void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
138 ASSERT(prec >= 0 && prec < pq->num_prec);
146 q->head = PKTLINK(p);
159 void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
164 ASSERT(prec >= 0 && prec < pq->num_prec);
172 for (prev = NULL; p != q->tail; p = PKTLINK(p))
176 PKTSETLINK(prev, NULL);
189 void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
197 q->head = PKTLINK(p);
199 PKTFREE(osh, p, dir);
208 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
211 for (prec = 0; prec < pq->num_prec; prec++)
212 pktq_pflush(osh, pq, prec, dir);
213 ASSERT(pq->len == 0);
215 #else /* !BRCM_FULLMAC */
217 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
221 void *p, *prev = NULL;
226 if (fn == NULL || (*fn) (p, arg)) {
227 bool head = (p == q->head);
229 q->head = PKTLINK(p);
231 PKTSETLINK(prev, PKTLINK(p));
233 PKTFREE(osh, p, dir);
236 p = (head ? q->head : PKTLINK(prev));
243 if (q->head == NULL) {
249 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
252 for (prec = 0; prec < pq->num_prec; prec++)
253 pktq_pflush(osh, pq, prec, dir, fn, arg);
255 ASSERT(pq->len == 0);
257 #endif /* BRCM_FULLMAC */
259 void pktq_init(struct pktq *pq, int num_prec, int max_len)
263 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
265 /* pq is variable size; only zero out what's requested */
267 offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
269 pq->num_prec = (u16) num_prec;
271 pq->max = (u16) max_len;
273 for (prec = 0; prec < num_prec; prec++)
274 pq->q[prec].max = pq->max;
277 void *pktq_peek_tail(struct pktq *pq, int *prec_out)
284 for (prec = 0; prec < pq->hi_prec; prec++)
285 if (pq->q[prec].head)
291 return pq->q[prec].tail;
294 /* Return sum of lengths of a specific set of precedences */
295 int pktq_mlen(struct pktq *pq, uint prec_bmp)
301 for (prec = 0; prec <= pq->hi_prec; prec++)
302 if (prec_bmp & (1 << prec))
303 len += pq->q[prec].len;
307 /* Priority dequeue from a specific set of precedences */
308 void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
317 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
320 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
330 q->head = PKTLINK(p);
346 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
347 int bcm_ether_atoe(char *p, struct ether_addr *ea)
352 ea->octet[i++] = (char)simple_strtoul(p, &p, 16);
361 * Search the name=value vars for a specific one and return its value.
362 * Returns NULL if not found.
364 char *getvar(char *vars, const char *name)
376 /* first look in vars[] */
377 for (s = vars; s && *s;) {
378 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
387 /* then query nvram */
388 return nvram_get(name);
393 * Search the vars for a specific one and return its value as
394 * an integer. Returns 0 if not found.
396 int getintvar(char *vars, const char *name)
400 val = getvar(vars, name);
404 return simple_strtoul(val, NULL, 0);
408 /* pretty hex print a pkt buffer chain */
409 void prpkt(const char *msg, osl_t *osh, void *p0)
413 if (msg && (msg[0] != '\0'))
414 printf("%s:\n", msg);
416 for (p = p0; p; p = PKTNEXT(p))
417 prhex(NULL, PKTDATA(p), PKTLEN(p));
419 #endif /* defined(BCMDBG) */
421 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
422 * Also updates the inplace vlan tag if requested.
423 * For debugging, it returns an indication of what it did.
425 uint pktsetprio(void *pkt, bool update_vtag)
427 struct ether_header *eh;
428 struct ethervlan_header *evh;
433 pktdata = (u8 *) PKTDATA(pkt);
434 ASSERT(IS_ALIGNED((unsigned long)pktdata, sizeof(u16)));
436 eh = (struct ether_header *)pktdata;
438 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
440 int vlan_prio, dscp_prio = 0;
442 evh = (struct ethervlan_header *)eh;
444 vlan_tag = ntoh16(evh->vlan_tag);
445 vlan_prio = (int)(vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
447 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
449 pktdata + sizeof(struct ethervlan_header);
450 u8 tos_tc = IP_TOS(ip_body);
451 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
454 /* DSCP priority gets precedence over 802.1P (vlan tag) */
455 if (dscp_prio != 0) {
456 priority = dscp_prio;
459 priority = vlan_prio;
463 * If the DSCP priority is not the same as the VLAN priority,
464 * then overwrite the priority field in the vlan tag, with the
465 * DSCP priority value. This is required for Linux APs because
466 * the VLAN driver on Linux, overwrites the skb->priority field
467 * with the priority value in the vlan tag
469 if (update_vtag && (priority != vlan_prio)) {
470 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
471 vlan_tag |= (u16) priority << VLAN_PRI_SHIFT;
472 evh->vlan_tag = hton16(vlan_tag);
475 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
476 u8 *ip_body = pktdata + sizeof(struct ether_header);
477 u8 tos_tc = IP_TOS(ip_body);
478 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
482 ASSERT(priority >= 0 && priority <= MAXPRIO);
483 PKTSETPRIO(pkt, priority);
484 return rc | priority;
487 static char bcm_undeferrstr[BCME_STRLEN];
489 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
491 /* Convert the error codes into related error strings */
492 const char *bcmerrorstr(int bcmerror)
494 /* check if someone added a bcmerror code but
495 forgot to add errorstring */
496 ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
498 if (bcmerror > 0 || bcmerror < BCME_LAST) {
499 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
501 return bcm_undeferrstr;
504 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
506 return bcmerrorstrtable[-bcmerror];
509 /* iovar table lookup */
510 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
512 const bcm_iovar_t *vi;
513 const char *lookup_name;
515 /* skip any ':' delimited option prefixes */
516 lookup_name = strrchr(name, ':');
517 if (lookup_name != NULL)
522 ASSERT(table != NULL);
524 for (vi = table; vi->name; vi++) {
525 if (!strcmp(vi->name, lookup_name))
528 /* ran to end of table */
530 return NULL; /* var name not found */
533 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
537 /* length check on io buf */
546 /* all integers are s32 sized args at the ioctl interface */
547 if (len < (int)sizeof(int)) {
548 bcmerror = BCME_BUFTOOSHORT;
553 /* buffer must meet minimum length requirement */
554 if (len < vi->minlen) {
555 bcmerror = BCME_BUFTOOSHORT;
561 /* Cannot return nil... */
562 bcmerror = BCME_UNSUPPORTED;
564 /* Set is an action w/o parameters */
565 bcmerror = BCME_BUFTOOLONG;
570 /* unknown type for length check in iovar info */
572 bcmerror = BCME_UNSUPPORTED;
578 /*******************************************************************************
581 * Computes a crc8 over the input data using the polynomial:
583 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
585 * The caller provides the initial value (either CRC8_INIT_VALUE
586 * or the previous returned value) to allow for processing of
587 * discontiguous blocks of data. When generating the CRC the
588 * caller is responsible for complementing the final return value
589 * and inserting it into the byte stream. When checking, a final
590 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
592 * Reference: Dallas Semiconductor Application Note 27
593 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
594 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
595 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
597 * ****************************************************************************
600 static const u8 crc8_table[256] = {
601 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
602 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
603 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
604 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
605 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
606 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
607 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
608 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
609 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
610 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
611 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
612 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
613 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
614 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
615 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
616 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
617 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
618 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
619 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
620 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
621 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
622 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
623 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
624 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
625 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
626 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
627 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
628 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
629 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
630 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
631 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
632 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
635 #define CRC_INNER_LOOP(n, c, x) \
636 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
638 u8 hndcrc8(u8 *pdata, /* pointer to array of data to process */
639 uint nbytes, /* number of input data bytes to process */
640 u8 crc /* either CRC8_INIT_VALUE or previous return value */
642 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
643 * to avoid the undefined and unnecessary (u8 >> 8) operation.
646 crc = crc8_table[(crc ^ *pdata++) & 0xff];
651 /*******************************************************************************
654 * Computes a crc16 over the input data using the polynomial:
656 * x^16 + x^12 +x^5 + 1
658 * The caller provides the initial value (either CRC16_INIT_VALUE
659 * or the previous returned value) to allow for processing of
660 * discontiguous blocks of data. When generating the CRC the
661 * caller is responsible for complementing the final return value
662 * and inserting it into the byte stream. When checking, a final
663 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
665 * Reference: Dallas Semiconductor Application Note 27
666 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
667 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
668 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
670 * ****************************************************************************
673 static const u16 crc16_table[256] = {
674 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
675 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
676 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
677 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
678 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
679 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
680 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
681 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
682 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
683 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
684 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
685 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
686 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
687 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
688 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
689 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
690 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
691 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
692 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
693 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
694 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
695 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
696 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
697 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
698 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
699 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
700 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
701 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
702 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
703 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
704 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
705 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
708 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
709 uint nbytes, /* number of input data bytes to process */
710 u16 crc /* either CRC16_INIT_VALUE or previous return value */
713 CRC_INNER_LOOP(16, crc, *pdata++);
717 static const u32 crc32_table[256] = {
718 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
719 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
720 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
721 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
722 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
723 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
724 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
725 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
726 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
727 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
728 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
729 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
730 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
731 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
732 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
733 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
734 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
735 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
736 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
737 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
738 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
739 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
740 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
741 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
742 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
743 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
744 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
745 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
746 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
747 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
748 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
749 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
750 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
751 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
752 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
753 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
754 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
755 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
756 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
757 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
758 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
759 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
760 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
761 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
762 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
763 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
764 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
765 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
766 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
767 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
768 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
769 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
770 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
771 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
772 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
773 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
774 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
775 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
776 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
777 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
778 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
779 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
780 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
781 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
784 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
785 uint nbytes, /* number of input data bytes to process */
786 u32 crc /* either CRC32_INIT_VALUE or previous
793 unsigned long *tptr = (unsigned long *) tmp;
795 /* in case the beginning of the buffer isn't aligned */
796 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
797 nbytes -= (pend - pdata);
799 CRC_INNER_LOOP(32, crc, *pdata++);
801 /* handle bulk of data as 32-bit words */
802 pend = pdata + (nbytes & 0xfffffffc);
803 while (pdata < pend) {
804 *tptr = *(unsigned long *) pdata;
805 pdata += sizeof(unsigned long *);
806 CRC_INNER_LOOP(32, crc, tmp[0]);
807 CRC_INNER_LOOP(32, crc, tmp[1]);
808 CRC_INNER_LOOP(32, crc, tmp[2]);
809 CRC_INNER_LOOP(32, crc, tmp[3]);
812 /* 1-3 bytes at end of buffer */
813 pend = pdata + (nbytes & 0x03);
815 CRC_INNER_LOOP(32, crc, *pdata++);
817 pend = pdata + nbytes;
819 CRC_INNER_LOOP(32, crc, *pdata++);
820 #endif /* __mips__ */
825 * Traverse a string of 1-byte tag/1-byte length/variable-length value
826 * triples, returning a pointer to the substring whose first element
829 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
834 elt = (bcm_tlv_t *) buf;
837 /* find tagged parameter */
838 while (totlen >= 2) {
841 /* validate remaining totlen */
842 if ((elt->id == key) && (totlen >= (len + 2)))
845 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
855 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
860 int slen = 0, nlen = 0;
869 for (i = 0; flags != 0; i++) {
872 if (bit == 0 && flags != 0) {
873 /* print any unnamed bits */
874 snprintf(hexstr, 16, "0x%X", flags);
876 flags = 0; /* exit loop */
877 } else if ((flags & bit) == 0)
882 /* count btwn flag space */
885 /* need NULL char as well */
888 /* copy NULL char but don't count it */
889 strncpy(p, name, nlen + 1);
891 /* copy btwn flag space and NULL char */
893 p += snprintf(p, 2, " ");
897 /* indicate the str was too short */
900 p -= 2 - len; /* overwrite last char */
901 p += snprintf(p, 2, ">");
904 return (int)(p - buf);
907 /* print bytes formatted as hex to a string. return the resulting string length */
908 int bcm_format_hex(char *str, const void *bytes, int len)
912 const u8 *src = (const u8 *)bytes;
914 for (i = 0; i < len; i++) {
915 p += snprintf(p, 3, "%02X", *src);
918 return (int)(p - str);
920 #endif /* defined(BCMDBG) */
922 /* pretty hex print a contiguous buffer */
923 void prhex(const char *msg, unsigned char *buf, uint nbytes)
926 int len = sizeof(line);
930 if (msg && (msg[0] != '\0'))
931 printf("%s:\n", msg);
934 for (i = 0; i < nbytes; i++) {
936 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
941 nchar = snprintf(p, len, "%02x ", buf[i]);
947 printf("%s\n", line); /* flush line */
953 /* flush last partial line */
955 printf("%s\n", line);
958 char *bcm_chipname(uint chipid, char *buf, uint len)
962 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
963 snprintf(buf, len, fmt, chipid);
967 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
971 len = strlen(name) + 1;
973 if ((len + datalen) > buflen)
976 strncpy(buf, name, buflen);
978 /* append data onto the end of the name string */
979 memcpy(&buf[len], data, datalen);
985 /* Quarter dBm units to mW
986 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
987 * Table is offset so the last entry is largest mW value that fits in
991 #define QDBM_OFFSET 153 /* Offset for first entry */
992 #define QDBM_TABLE_LEN 40 /* Table size */
994 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
995 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
997 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
999 /* Largest mW value that will round down to the last table entry,
1000 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1001 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
1002 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1004 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1006 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1007 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1008 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1009 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1010 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1011 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1012 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1015 u16 bcm_qdbm_to_mw(u8 qdbm)
1018 int idx = qdbm - QDBM_OFFSET;
1020 if (idx >= QDBM_TABLE_LEN) {
1021 /* clamp to max u16 mW value */
1025 /* scale the qdBm index up to the range of the table 0-40
1026 * where an offset of 40 qdBm equals a factor of 10 mW.
1033 /* return the mW value scaled down to the correct factor of 10,
1034 * adding in factor/2 to get proper rounding.
1036 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
1038 u8 bcm_mw_to_qdbm(u16 mw)
1045 /* handle boundary case */
1049 offset = QDBM_OFFSET;
1051 /* move mw into the range of the table */
1052 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1057 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1058 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1059 nqdBm_to_mW_map[qdbm]) / 2;
1060 if (mw_uint < boundary)
1064 qdbm += (u8) offset;
1068 uint bcm_bitcount(u8 *bitmap, uint length)
1070 uint bitcount = 0, i;
1072 for (i = 0; i < length; i++) {
1081 /* Initialization of bcmstrbuf structure */
1082 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1084 b->origsize = b->size = size;
1085 b->origbuf = b->buf = buf;
1088 /* Buffer sprintf wrapper to guard against buffer overflow */
1089 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1095 r = vsnprintf(b->buf, b->size, fmt, ap);
1097 /* Non Ansi C99 compliant returns -1,
1098 * Ansi compliant return r >= b->size,
1099 * bcmstdlib returns 0, handle all
1101 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {