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/802.1d.h>
31 #include <proto/802.11.h>
34 /* copy a buffer into a pkt buffer chain */
35 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf)
39 /* skip 'offset' bytes */
40 for (; p && offset; p = PKTNEXT(p)) {
41 if (offset < (uint) PKTLEN(p))
50 for (; p && len; p = PKTNEXT(p)) {
51 n = min((uint) PKTLEN(p) - offset, (uint) len);
52 bcopy(buf, PKTDATA(p) + offset, n);
61 /* return total length of buffer chain */
62 uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
67 for (; p; p = PKTNEXT(p))
73 * osl multiple-precedence packet queue
74 * hi_prec is always >= the number of the highest non-empty precedence
76 void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
80 ASSERT(prec >= 0 && prec < pq->num_prec);
81 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
83 ASSERT(!pktq_full(pq));
84 ASSERT(!pktq_pfull(pq, prec));
89 PKTSETLINK(q->tail, p);
98 if (pq->hi_prec < prec)
99 pq->hi_prec = (u8) prec;
104 void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p)
108 ASSERT(prec >= 0 && prec < pq->num_prec);
109 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
111 ASSERT(!pktq_full(pq));
112 ASSERT(!pktq_pfull(pq, prec));
119 PKTSETLINK(p, q->head);
125 if (pq->hi_prec < prec)
126 pq->hi_prec = (u8) prec;
131 void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
136 ASSERT(prec >= 0 && prec < pq->num_prec);
144 q->head = PKTLINK(p);
157 void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
162 ASSERT(prec >= 0 && prec < pq->num_prec);
170 for (prev = NULL; p != q->tail; p = PKTLINK(p))
174 PKTSETLINK(prev, NULL);
187 void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
195 q->head = PKTLINK(p);
197 PKTFREE(osh, p, dir);
206 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
209 for (prec = 0; prec < pq->num_prec; prec++)
210 pktq_pflush(osh, pq, prec, dir);
211 ASSERT(pq->len == 0);
213 #else /* !BRCM_FULLMAC */
215 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
219 void *p, *prev = NULL;
224 if (fn == NULL || (*fn) (p, arg)) {
225 bool head = (p == q->head);
227 q->head = PKTLINK(p);
229 PKTSETLINK(prev, PKTLINK(p));
231 PKTFREE(osh, p, dir);
234 p = (head ? q->head : PKTLINK(prev));
241 if (q->head == NULL) {
247 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
250 for (prec = 0; prec < pq->num_prec; prec++)
251 pktq_pflush(osh, pq, prec, dir, fn, arg);
253 ASSERT(pq->len == 0);
255 #endif /* BRCM_FULLMAC */
257 void pktq_init(struct pktq *pq, int num_prec, int max_len)
261 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
263 /* pq is variable size; only zero out what's requested */
265 offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
267 pq->num_prec = (u16) num_prec;
269 pq->max = (u16) max_len;
271 for (prec = 0; prec < num_prec; prec++)
272 pq->q[prec].max = pq->max;
275 void *pktq_peek_tail(struct pktq *pq, int *prec_out)
282 for (prec = 0; prec < pq->hi_prec; prec++)
283 if (pq->q[prec].head)
289 return pq->q[prec].tail;
292 /* Return sum of lengths of a specific set of precedences */
293 int pktq_mlen(struct pktq *pq, uint prec_bmp)
299 for (prec = 0; prec <= pq->hi_prec; prec++)
300 if (prec_bmp & (1 << prec))
301 len += pq->q[prec].len;
305 /* Priority dequeue from a specific set of precedences */
306 void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
315 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
318 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
328 q->head = PKTLINK(p);
344 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
345 int bcm_ether_atoe(char *p, struct ether_addr *ea)
350 ea->octet[i++] = (char)simple_strtoul(p, &p, 16);
359 * Search the name=value vars for a specific one and return its value.
360 * Returns NULL if not found.
362 char *getvar(char *vars, const char *name)
374 /* first look in vars[] */
375 for (s = vars; s && *s;) {
376 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
385 /* then query nvram */
386 return nvram_get(name);
391 * Search the vars for a specific one and return its value as
392 * an integer. Returns 0 if not found.
394 int getintvar(char *vars, const char *name)
398 val = getvar(vars, name);
402 return simple_strtoul(val, NULL, 0);
406 /* pretty hex print a pkt buffer chain */
407 void prpkt(const char *msg, osl_t *osh, void *p0)
411 if (msg && (msg[0] != '\0'))
412 printf("%s:\n", msg);
414 for (p = p0; p; p = PKTNEXT(p))
415 prhex(NULL, PKTDATA(p), PKTLEN(p));
417 #endif /* defined(BCMDBG) */
419 static char bcm_undeferrstr[BCME_STRLEN];
421 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
423 /* Convert the error codes into related error strings */
424 const char *bcmerrorstr(int bcmerror)
426 /* check if someone added a bcmerror code but
427 forgot to add errorstring */
428 ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
430 if (bcmerror > 0 || bcmerror < BCME_LAST) {
431 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
433 return bcm_undeferrstr;
436 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
438 return bcmerrorstrtable[-bcmerror];
441 /* iovar table lookup */
442 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
444 const bcm_iovar_t *vi;
445 const char *lookup_name;
447 /* skip any ':' delimited option prefixes */
448 lookup_name = strrchr(name, ':');
449 if (lookup_name != NULL)
454 ASSERT(table != NULL);
456 for (vi = table; vi->name; vi++) {
457 if (!strcmp(vi->name, lookup_name))
460 /* ran to end of table */
462 return NULL; /* var name not found */
465 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
469 /* length check on io buf */
478 /* all integers are s32 sized args at the ioctl interface */
479 if (len < (int)sizeof(int)) {
480 bcmerror = BCME_BUFTOOSHORT;
485 /* buffer must meet minimum length requirement */
486 if (len < vi->minlen) {
487 bcmerror = BCME_BUFTOOSHORT;
493 /* Cannot return nil... */
494 bcmerror = BCME_UNSUPPORTED;
496 /* Set is an action w/o parameters */
497 bcmerror = BCME_BUFTOOLONG;
502 /* unknown type for length check in iovar info */
504 bcmerror = BCME_UNSUPPORTED;
510 /*******************************************************************************
513 * Computes a crc8 over the input data using the polynomial:
515 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
517 * The caller provides the initial value (either CRC8_INIT_VALUE
518 * or the previous returned value) to allow for processing of
519 * discontiguous blocks of data. When generating the CRC the
520 * caller is responsible for complementing the final return value
521 * and inserting it into the byte stream. When checking, a final
522 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
524 * Reference: Dallas Semiconductor Application Note 27
525 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
526 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
527 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
529 * ****************************************************************************
532 static const u8 crc8_table[256] = {
533 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
534 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
535 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
536 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
537 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
538 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
539 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
540 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
541 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
542 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
543 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
544 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
545 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
546 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
547 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
548 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
549 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
550 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
551 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
552 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
553 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
554 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
555 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
556 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
557 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
558 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
559 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
560 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
561 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
562 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
563 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
564 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
567 #define CRC_INNER_LOOP(n, c, x) \
568 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
570 u8 hndcrc8(u8 *pdata, /* pointer to array of data to process */
571 uint nbytes, /* number of input data bytes to process */
572 u8 crc /* either CRC8_INIT_VALUE or previous return value */
574 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
575 * to avoid the undefined and unnecessary (u8 >> 8) operation.
578 crc = crc8_table[(crc ^ *pdata++) & 0xff];
583 /*******************************************************************************
586 * Computes a crc16 over the input data using the polynomial:
588 * x^16 + x^12 +x^5 + 1
590 * The caller provides the initial value (either CRC16_INIT_VALUE
591 * or the previous returned value) to allow for processing of
592 * discontiguous blocks of data. When generating the CRC the
593 * caller is responsible for complementing the final return value
594 * and inserting it into the byte stream. When checking, a final
595 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
597 * Reference: Dallas Semiconductor Application Note 27
598 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
599 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
600 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
602 * ****************************************************************************
605 static const u16 crc16_table[256] = {
606 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
607 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
608 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
609 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
610 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
611 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
612 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
613 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
614 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
615 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
616 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
617 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
618 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
619 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
620 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
621 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
622 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
623 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
624 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
625 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
626 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
627 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
628 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
629 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
630 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
631 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
632 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
633 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
634 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
635 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
636 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
637 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
640 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
641 uint nbytes, /* number of input data bytes to process */
642 u16 crc /* either CRC16_INIT_VALUE or previous return value */
645 CRC_INNER_LOOP(16, crc, *pdata++);
649 static const u32 crc32_table[256] = {
650 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
651 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
652 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
653 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
654 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
655 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
656 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
657 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
658 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
659 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
660 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
661 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
662 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
663 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
664 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
665 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
666 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
667 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
668 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
669 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
670 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
671 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
672 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
673 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
674 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
675 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
676 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
677 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
678 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
679 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
680 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
681 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
682 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
683 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
684 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
685 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
686 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
687 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
688 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
689 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
690 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
691 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
692 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
693 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
694 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
695 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
696 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
697 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
698 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
699 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
700 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
701 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
702 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
703 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
704 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
705 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
706 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
707 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
708 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
709 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
710 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
711 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
712 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
713 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
716 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
717 uint nbytes, /* number of input data bytes to process */
718 u32 crc /* either CRC32_INIT_VALUE or previous
725 unsigned long *tptr = (unsigned long *) tmp;
727 /* in case the beginning of the buffer isn't aligned */
728 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
729 nbytes -= (pend - pdata);
731 CRC_INNER_LOOP(32, crc, *pdata++);
733 /* handle bulk of data as 32-bit words */
734 pend = pdata + (nbytes & 0xfffffffc);
735 while (pdata < pend) {
736 *tptr = *(unsigned long *) pdata;
737 pdata += sizeof(unsigned long *);
738 CRC_INNER_LOOP(32, crc, tmp[0]);
739 CRC_INNER_LOOP(32, crc, tmp[1]);
740 CRC_INNER_LOOP(32, crc, tmp[2]);
741 CRC_INNER_LOOP(32, crc, tmp[3]);
744 /* 1-3 bytes at end of buffer */
745 pend = pdata + (nbytes & 0x03);
747 CRC_INNER_LOOP(32, crc, *pdata++);
749 pend = pdata + nbytes;
751 CRC_INNER_LOOP(32, crc, *pdata++);
752 #endif /* __mips__ */
757 * Traverse a string of 1-byte tag/1-byte length/variable-length value
758 * triples, returning a pointer to the substring whose first element
761 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
766 elt = (bcm_tlv_t *) buf;
769 /* find tagged parameter */
770 while (totlen >= 2) {
773 /* validate remaining totlen */
774 if ((elt->id == key) && (totlen >= (len + 2)))
777 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
787 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
792 int slen = 0, nlen = 0;
801 for (i = 0; flags != 0; i++) {
804 if (bit == 0 && flags != 0) {
805 /* print any unnamed bits */
806 snprintf(hexstr, 16, "0x%X", flags);
808 flags = 0; /* exit loop */
809 } else if ((flags & bit) == 0)
814 /* count btwn flag space */
817 /* need NULL char as well */
820 /* copy NULL char but don't count it */
821 strncpy(p, name, nlen + 1);
823 /* copy btwn flag space and NULL char */
825 p += snprintf(p, 2, " ");
829 /* indicate the str was too short */
832 p -= 2 - len; /* overwrite last char */
833 p += snprintf(p, 2, ">");
836 return (int)(p - buf);
839 /* print bytes formatted as hex to a string. return the resulting string length */
840 int bcm_format_hex(char *str, const void *bytes, int len)
844 const u8 *src = (const u8 *)bytes;
846 for (i = 0; i < len; i++) {
847 p += snprintf(p, 3, "%02X", *src);
850 return (int)(p - str);
852 #endif /* defined(BCMDBG) */
854 /* pretty hex print a contiguous buffer */
855 void prhex(const char *msg, unsigned char *buf, uint nbytes)
858 int len = sizeof(line);
862 if (msg && (msg[0] != '\0'))
863 printf("%s:\n", msg);
866 for (i = 0; i < nbytes; i++) {
868 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
873 nchar = snprintf(p, len, "%02x ", buf[i]);
879 printf("%s\n", line); /* flush line */
885 /* flush last partial line */
887 printf("%s\n", line);
890 char *bcm_chipname(uint chipid, char *buf, uint len)
894 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
895 snprintf(buf, len, fmt, chipid);
899 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
903 len = strlen(name) + 1;
905 if ((len + datalen) > buflen)
908 strncpy(buf, name, buflen);
910 /* append data onto the end of the name string */
911 memcpy(&buf[len], data, datalen);
917 /* Quarter dBm units to mW
918 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
919 * Table is offset so the last entry is largest mW value that fits in
923 #define QDBM_OFFSET 153 /* Offset for first entry */
924 #define QDBM_TABLE_LEN 40 /* Table size */
926 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
927 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
929 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
931 /* Largest mW value that will round down to the last table entry,
932 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
933 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
934 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
936 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
938 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
939 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
940 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
941 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
942 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
943 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
944 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
947 u16 bcm_qdbm_to_mw(u8 qdbm)
950 int idx = qdbm - QDBM_OFFSET;
952 if (idx >= QDBM_TABLE_LEN) {
953 /* clamp to max u16 mW value */
957 /* scale the qdBm index up to the range of the table 0-40
958 * where an offset of 40 qdBm equals a factor of 10 mW.
965 /* return the mW value scaled down to the correct factor of 10,
966 * adding in factor/2 to get proper rounding.
968 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
970 u8 bcm_mw_to_qdbm(u16 mw)
977 /* handle boundary case */
981 offset = QDBM_OFFSET;
983 /* move mw into the range of the table */
984 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
989 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
990 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
991 nqdBm_to_mW_map[qdbm]) / 2;
992 if (mw_uint < boundary)
1000 uint bcm_bitcount(u8 *bitmap, uint length)
1002 uint bitcount = 0, i;
1004 for (i = 0; i < length; i++) {
1013 /* Initialization of bcmstrbuf structure */
1014 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1016 b->origsize = b->size = size;
1017 b->origbuf = b->buf = buf;
1020 /* Buffer sprintf wrapper to guard against buffer overflow */
1021 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1027 r = vsnprintf(b->buf, b->size, fmt, ap);
1029 /* Non Ansi C99 compliant returns -1,
1030 * Ansi compliant return r >= b->size,
1031 * bcmstdlib returns 0, handle all
1033 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {