2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/ctype.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
22 #include <linux/module.h>
23 #include <linux/pci.h>
24 #include <linux/netdevice.h>
29 #include <bcmendian.h>
31 #include <proto/ethernet.h>
32 #include <proto/802.1d.h>
33 #include <proto/802.11.h>
35 /* copy a buffer into a pkt buffer chain */
36 uint pktfrombuf(struct osl_info *osh, void *p, uint offset, int len,
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(struct osl_info *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(struct osl_info *osh, struct pktq *pq, int prec, bool dir)
197 q->head = PKTLINK(p);
199 PKTFREE(osh, p, dir);
208 void pktq_flush(struct osl_info *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(struct osl_info *osh, struct pktq *pq, int prec, bool dir,
218 ifpkt_cb_t fn, int arg)
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(struct osl_info *osh, struct pktq *pq, bool dir,
250 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, struct osl_info *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 static char bcm_undeferrstr[BCME_STRLEN];
424 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
426 /* Convert the error codes into related error strings */
427 const char *bcmerrorstr(int bcmerror)
429 /* check if someone added a bcmerror code but
430 forgot to add errorstring */
431 ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
433 if (bcmerror > 0 || bcmerror < BCME_LAST) {
434 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
436 return bcm_undeferrstr;
439 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
441 return bcmerrorstrtable[-bcmerror];
444 /* iovar table lookup */
445 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
447 const bcm_iovar_t *vi;
448 const char *lookup_name;
450 /* skip any ':' delimited option prefixes */
451 lookup_name = strrchr(name, ':');
452 if (lookup_name != NULL)
457 ASSERT(table != NULL);
459 for (vi = table; vi->name; vi++) {
460 if (!strcmp(vi->name, lookup_name))
463 /* ran to end of table */
465 return NULL; /* var name not found */
468 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
472 /* length check on io buf */
481 /* all integers are s32 sized args at the ioctl interface */
482 if (len < (int)sizeof(int)) {
483 bcmerror = BCME_BUFTOOSHORT;
488 /* buffer must meet minimum length requirement */
489 if (len < vi->minlen) {
490 bcmerror = BCME_BUFTOOSHORT;
496 /* Cannot return nil... */
497 bcmerror = BCME_UNSUPPORTED;
499 /* Set is an action w/o parameters */
500 bcmerror = BCME_BUFTOOLONG;
505 /* unknown type for length check in iovar info */
507 bcmerror = BCME_UNSUPPORTED;
513 /*******************************************************************************
516 * Computes a crc8 over the input data using the polynomial:
518 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
520 * The caller provides the initial value (either CRC8_INIT_VALUE
521 * or the previous returned value) to allow for processing of
522 * discontiguous blocks of data. When generating the CRC the
523 * caller is responsible for complementing the final return value
524 * and inserting it into the byte stream. When checking, a final
525 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
527 * Reference: Dallas Semiconductor Application Note 27
528 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
529 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
530 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
532 * ****************************************************************************
535 static const u8 crc8_table[256] = {
536 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
537 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
538 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
539 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
540 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
541 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
542 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
543 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
544 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
545 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
546 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
547 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
548 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
549 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
550 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
551 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
552 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
553 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
554 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
555 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
556 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
557 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
558 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
559 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
560 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
561 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
562 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
563 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
564 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
565 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
566 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
567 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
570 #define CRC_INNER_LOOP(n, c, x) \
571 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
573 u8 hndcrc8(u8 *pdata, /* pointer to array of data to process */
574 uint nbytes, /* number of input data bytes to process */
575 u8 crc /* either CRC8_INIT_VALUE or previous return value */
577 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
578 * to avoid the undefined and unnecessary (u8 >> 8) operation.
581 crc = crc8_table[(crc ^ *pdata++) & 0xff];
586 /*******************************************************************************
589 * Computes a crc16 over the input data using the polynomial:
591 * x^16 + x^12 +x^5 + 1
593 * The caller provides the initial value (either CRC16_INIT_VALUE
594 * or the previous returned value) to allow for processing of
595 * discontiguous blocks of data. When generating the CRC the
596 * caller is responsible for complementing the final return value
597 * and inserting it into the byte stream. When checking, a final
598 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
600 * Reference: Dallas Semiconductor Application Note 27
601 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
602 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
603 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
605 * ****************************************************************************
608 static const u16 crc16_table[256] = {
609 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
610 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
611 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
612 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
613 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
614 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
615 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
616 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
617 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
618 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
619 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
620 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
621 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
622 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
623 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
624 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
625 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
626 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
627 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
628 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
629 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
630 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
631 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
632 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
633 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
634 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
635 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
636 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
637 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
638 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
639 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
640 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
643 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
644 uint nbytes, /* number of input data bytes to process */
645 u16 crc /* either CRC16_INIT_VALUE or previous return value */
648 CRC_INNER_LOOP(16, crc, *pdata++);
652 static const u32 crc32_table[256] = {
653 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
654 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
655 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
656 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
657 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
658 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
659 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
660 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
661 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
662 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
663 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
664 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
665 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
666 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
667 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
668 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
669 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
670 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
671 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
672 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
673 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
674 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
675 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
676 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
677 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
678 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
679 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
680 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
681 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
682 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
683 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
684 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
685 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
686 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
687 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
688 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
689 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
690 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
691 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
692 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
693 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
694 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
695 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
696 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
697 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
698 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
699 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
700 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
701 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
702 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
703 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
704 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
705 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
706 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
707 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
708 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
709 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
710 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
711 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
712 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
713 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
714 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
715 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
716 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
719 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
720 uint nbytes, /* number of input data bytes to process */
721 u32 crc /* either CRC32_INIT_VALUE or previous
728 unsigned long *tptr = (unsigned long *) tmp;
730 /* in case the beginning of the buffer isn't aligned */
731 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
732 nbytes -= (pend - pdata);
734 CRC_INNER_LOOP(32, crc, *pdata++);
736 /* handle bulk of data as 32-bit words */
737 pend = pdata + (nbytes & 0xfffffffc);
738 while (pdata < pend) {
739 *tptr = *(unsigned long *) pdata;
740 pdata += sizeof(unsigned long *);
741 CRC_INNER_LOOP(32, crc, tmp[0]);
742 CRC_INNER_LOOP(32, crc, tmp[1]);
743 CRC_INNER_LOOP(32, crc, tmp[2]);
744 CRC_INNER_LOOP(32, crc, tmp[3]);
747 /* 1-3 bytes at end of buffer */
748 pend = pdata + (nbytes & 0x03);
750 CRC_INNER_LOOP(32, crc, *pdata++);
752 pend = pdata + nbytes;
754 CRC_INNER_LOOP(32, crc, *pdata++);
755 #endif /* __mips__ */
760 * Traverse a string of 1-byte tag/1-byte length/variable-length value
761 * triples, returning a pointer to the substring whose first element
764 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
769 elt = (bcm_tlv_t *) buf;
772 /* find tagged parameter */
773 while (totlen >= 2) {
776 /* validate remaining totlen */
777 if ((elt->id == key) && (totlen >= (len + 2)))
780 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
790 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
795 int slen = 0, nlen = 0;
804 for (i = 0; flags != 0; i++) {
807 if (bit == 0 && flags != 0) {
808 /* print any unnamed bits */
809 snprintf(hexstr, 16, "0x%X", flags);
811 flags = 0; /* exit loop */
812 } else if ((flags & bit) == 0)
817 /* count btwn flag space */
820 /* need NULL char as well */
823 /* copy NULL char but don't count it */
824 strncpy(p, name, nlen + 1);
826 /* copy btwn flag space and NULL char */
828 p += snprintf(p, 2, " ");
832 /* indicate the str was too short */
835 p -= 2 - len; /* overwrite last char */
836 p += snprintf(p, 2, ">");
839 return (int)(p - buf);
842 /* print bytes formatted as hex to a string. return the resulting string length */
843 int bcm_format_hex(char *str, const void *bytes, int len)
847 const u8 *src = (const u8 *)bytes;
849 for (i = 0; i < len; i++) {
850 p += snprintf(p, 3, "%02X", *src);
853 return (int)(p - str);
855 #endif /* defined(BCMDBG) */
857 /* pretty hex print a contiguous buffer */
858 void prhex(const char *msg, unsigned char *buf, uint nbytes)
861 int len = sizeof(line);
865 if (msg && (msg[0] != '\0'))
866 printf("%s:\n", msg);
869 for (i = 0; i < nbytes; i++) {
871 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
876 nchar = snprintf(p, len, "%02x ", buf[i]);
882 printf("%s\n", line); /* flush line */
888 /* flush last partial line */
890 printf("%s\n", line);
893 char *bcm_chipname(uint chipid, char *buf, uint len)
897 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
898 snprintf(buf, len, fmt, chipid);
902 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
906 len = strlen(name) + 1;
908 if ((len + datalen) > buflen)
911 strncpy(buf, name, buflen);
913 /* append data onto the end of the name string */
914 memcpy(&buf[len], data, datalen);
920 /* Quarter dBm units to mW
921 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
922 * Table is offset so the last entry is largest mW value that fits in
926 #define QDBM_OFFSET 153 /* Offset for first entry */
927 #define QDBM_TABLE_LEN 40 /* Table size */
929 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
930 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
932 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
934 /* Largest mW value that will round down to the last table entry,
935 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
936 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
937 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
939 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
941 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
942 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
943 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
944 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
945 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
946 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
947 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
950 u16 bcm_qdbm_to_mw(u8 qdbm)
953 int idx = qdbm - QDBM_OFFSET;
955 if (idx >= QDBM_TABLE_LEN) {
956 /* clamp to max u16 mW value */
960 /* scale the qdBm index up to the range of the table 0-40
961 * where an offset of 40 qdBm equals a factor of 10 mW.
968 /* return the mW value scaled down to the correct factor of 10,
969 * adding in factor/2 to get proper rounding.
971 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
973 u8 bcm_mw_to_qdbm(u16 mw)
980 /* handle boundary case */
984 offset = QDBM_OFFSET;
986 /* move mw into the range of the table */
987 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
992 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
993 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
994 nqdBm_to_mW_map[qdbm]) / 2;
995 if (mw_uint < boundary)
1003 uint bcm_bitcount(u8 *bitmap, uint length)
1005 uint bitcount = 0, i;
1007 for (i = 0; i < length; i++) {
1016 /* Initialization of bcmstrbuf structure */
1017 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1019 b->origsize = b->size = size;
1020 b->origbuf = b->buf = buf;
1023 /* Buffer sprintf wrapper to guard against buffer overflow */
1024 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1030 r = vsnprintf(b->buf, b->size, fmt, ap);
1032 /* Non Ansi C99 compliant returns -1,
1033 * Ansi compliant return r >= b->size,
1034 * bcmstdlib returns 0, handle all
1036 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {