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>
30 #include <proto/802.11.h>
32 struct sk_buff *BCMFASTPATH pkt_buf_get_skb(struct osl_info *osh, uint len)
36 skb = dev_alloc_skb(len);
47 /* Free the driver packet. Free the tag if present */
48 void BCMFASTPATH pkt_buf_free_skb(struct osl_info *osh,
49 struct sk_buff *skb, bool send)
56 /* perversion: we use skb->next to chain multi-skb packets */
62 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
65 dev_kfree_skb_any(skb);
67 /* can free immediately (even in_irq()) if destructor
78 /* copy a buffer into a pkt buffer chain */
79 uint pktfrombuf(struct sk_buff *p, uint offset, int len,
84 /* skip 'offset' bytes */
85 for (; p && offset; p = p->next) {
86 if (offset < (uint) (p->len))
95 for (; p && len; p = p->next) {
96 n = min((uint) (p->len) - offset, (uint) len);
97 memcpy(p->data + offset, buf, n);
106 /* return total length of buffer chain */
107 uint BCMFASTPATH pkttotlen(struct sk_buff *p)
112 for (; p; p = p->next)
118 * osl multiple-precedence packet queue
119 * hi_prec is always >= the number of the highest non-empty precedence
121 struct sk_buff *BCMFASTPATH pktq_penq(struct pktq *pq, int prec,
126 ASSERT(prec >= 0 && prec < pq->num_prec);
127 ASSERT(p->prev == NULL); /* queueing chains not allowed */
129 ASSERT(!pktq_full(pq));
130 ASSERT(!pktq_pfull(pq, prec));
144 if (pq->hi_prec < prec)
145 pq->hi_prec = (u8) prec;
150 struct sk_buff *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec,
155 ASSERT(prec >= 0 && prec < pq->num_prec);
156 ASSERT(p->prev == NULL); /* queueing chains not allowed */
158 ASSERT(!pktq_full(pq));
159 ASSERT(!pktq_pfull(pq, prec));
172 if (pq->hi_prec < prec)
173 pq->hi_prec = (u8) prec;
178 struct sk_buff *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
183 ASSERT(prec >= 0 && prec < pq->num_prec);
204 struct sk_buff *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
207 struct sk_buff *p, *prev;
209 ASSERT(prec >= 0 && prec < pq->num_prec);
217 for (prev = NULL; p != q->tail; p = p->prev)
234 void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir)
244 pkt_buf_free_skb(osh, p, dir);
253 void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir)
256 for (prec = 0; prec < pq->num_prec; prec++)
257 pktq_pflush(osh, pq, prec, dir);
258 ASSERT(pq->len == 0);
260 #else /* !BRCM_FULLMAC */
262 pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir,
263 ifpkt_cb_t fn, int arg)
266 struct sk_buff *p, *prev = NULL;
271 if (fn == NULL || (*fn) (p, arg)) {
272 bool head = (p == q->head);
276 prev->prev = p->prev;
278 pkt_buf_free_skb(osh, p, dir);
281 p = (head ? q->head : prev->prev);
288 if (q->head == NULL) {
294 void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir,
295 ifpkt_cb_t fn, int arg)
298 for (prec = 0; prec < pq->num_prec; prec++)
299 pktq_pflush(osh, pq, prec, dir, fn, arg);
301 ASSERT(pq->len == 0);
303 #endif /* BRCM_FULLMAC */
305 void pktq_init(struct pktq *pq, int num_prec, int max_len)
309 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
311 /* pq is variable size; only zero out what's requested */
313 offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
315 pq->num_prec = (u16) num_prec;
317 pq->max = (u16) max_len;
319 for (prec = 0; prec < num_prec; prec++)
320 pq->q[prec].max = pq->max;
323 struct sk_buff *pktq_peek_tail(struct pktq *pq, int *prec_out)
330 for (prec = 0; prec < pq->hi_prec; prec++)
331 if (pq->q[prec].head)
337 return pq->q[prec].tail;
340 /* Return sum of lengths of a specific set of precedences */
341 int pktq_mlen(struct pktq *pq, uint prec_bmp)
347 for (prec = 0; prec <= pq->hi_prec; prec++)
348 if (prec_bmp & (1 << prec))
349 len += pq->q[prec].len;
353 /* Priority dequeue from a specific set of precedences */
354 struct sk_buff *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp,
364 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
367 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
393 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
394 int bcm_ether_atoe(char *p, u8 *ea)
399 ea[i++] = (char)simple_strtoul(p, &p, 16);
408 * Search the name=value vars for a specific one and return its value.
409 * Returns NULL if not found.
411 char *getvar(char *vars, const char *name)
423 /* first look in vars[] */
424 for (s = vars; s && *s;) {
425 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
434 /* then query nvram */
435 return nvram_get(name);
440 * Search the vars for a specific one and return its value as
441 * an integer. Returns 0 if not found.
443 int getintvar(char *vars, const char *name)
447 val = getvar(vars, name);
451 return simple_strtoul(val, NULL, 0);
455 /* pretty hex print a pkt buffer chain */
456 void prpkt(const char *msg, struct sk_buff *p0)
460 if (msg && (msg[0] != '\0'))
461 printk(KERN_DEBUG "%s:\n", msg);
463 for (p = p0; p; p = p->next)
464 prhex(NULL, p->data, p->len);
466 #endif /* defined(BCMDBG) */
468 static char bcm_undeferrstr[BCME_STRLEN];
470 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
472 /* Convert the error codes into related error strings */
473 const char *bcmerrorstr(int bcmerror)
475 /* check if someone added a bcmerror code but
476 forgot to add errorstring */
477 ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
479 if (bcmerror > 0 || bcmerror < BCME_LAST) {
480 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
482 return bcm_undeferrstr;
485 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
487 return bcmerrorstrtable[-bcmerror];
490 /* iovar table lookup */
491 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
493 const bcm_iovar_t *vi;
494 const char *lookup_name;
496 /* skip any ':' delimited option prefixes */
497 lookup_name = strrchr(name, ':');
498 if (lookup_name != NULL)
503 ASSERT(table != NULL);
505 for (vi = table; vi->name; vi++) {
506 if (!strcmp(vi->name, lookup_name))
509 /* ran to end of table */
511 return NULL; /* var name not found */
514 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
518 /* length check on io buf */
527 /* all integers are s32 sized args at the ioctl interface */
528 if (len < (int)sizeof(int)) {
529 bcmerror = BCME_BUFTOOSHORT;
534 /* buffer must meet minimum length requirement */
535 if (len < vi->minlen) {
536 bcmerror = BCME_BUFTOOSHORT;
542 /* Cannot return nil... */
543 bcmerror = BCME_UNSUPPORTED;
545 /* Set is an action w/o parameters */
546 bcmerror = BCME_BUFTOOLONG;
551 /* unknown type for length check in iovar info */
553 bcmerror = BCME_UNSUPPORTED;
559 /*******************************************************************************
562 * Computes a crc8 over the input data using the polynomial:
564 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
566 * The caller provides the initial value (either CRC8_INIT_VALUE
567 * or the previous returned value) to allow for processing of
568 * discontiguous blocks of data. When generating the CRC the
569 * caller is responsible for complementing the final return value
570 * and inserting it into the byte stream. When checking, a final
571 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
573 * Reference: Dallas Semiconductor Application Note 27
574 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
575 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
576 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
578 * ****************************************************************************
581 static const u8 crc8_table[256] = {
582 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
583 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
584 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
585 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
586 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
587 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
588 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
589 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
590 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
591 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
592 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
593 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
594 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
595 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
596 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
597 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
598 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
599 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
600 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
601 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
602 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
603 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
604 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
605 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
606 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
607 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
608 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
609 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
610 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
611 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
612 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
613 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
616 #define CRC_INNER_LOOP(n, c, x) \
617 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
619 u8 hndcrc8(u8 *pdata, /* pointer to array of data to process */
620 uint nbytes, /* number of input data bytes to process */
621 u8 crc /* either CRC8_INIT_VALUE or previous return value */
623 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
624 * to avoid the undefined and unnecessary (u8 >> 8) operation.
627 crc = crc8_table[(crc ^ *pdata++) & 0xff];
632 /*******************************************************************************
635 * Computes a crc16 over the input data using the polynomial:
637 * x^16 + x^12 +x^5 + 1
639 * The caller provides the initial value (either CRC16_INIT_VALUE
640 * or the previous returned value) to allow for processing of
641 * discontiguous blocks of data. When generating the CRC the
642 * caller is responsible for complementing the final return value
643 * and inserting it into the byte stream. When checking, a final
644 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
646 * Reference: Dallas Semiconductor Application Note 27
647 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
648 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
649 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
651 * ****************************************************************************
654 static const u16 crc16_table[256] = {
655 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
656 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
657 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
658 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
659 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
660 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
661 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
662 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
663 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
664 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
665 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
666 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
667 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
668 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
669 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
670 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
671 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
672 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
673 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
674 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
675 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
676 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
677 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
678 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
679 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
680 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
681 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
682 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
683 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
684 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
685 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
686 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
689 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
690 uint nbytes, /* number of input data bytes to process */
691 u16 crc /* either CRC16_INIT_VALUE or previous return value */
694 CRC_INNER_LOOP(16, crc, *pdata++);
698 static const u32 crc32_table[256] = {
699 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
700 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
701 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
702 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
703 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
704 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
705 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
706 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
707 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
708 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
709 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
710 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
711 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
712 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
713 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
714 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
715 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
716 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
717 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
718 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
719 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
720 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
721 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
722 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
723 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
724 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
725 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
726 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
727 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
728 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
729 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
730 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
731 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
732 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
733 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
734 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
735 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
736 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
737 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
738 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
739 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
740 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
741 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
742 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
743 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
744 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
745 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
746 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
747 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
748 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
749 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
750 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
751 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
752 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
753 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
754 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
755 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
756 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
757 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
758 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
759 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
760 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
761 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
762 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
765 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
766 uint nbytes, /* number of input data bytes to process */
767 u32 crc /* either CRC32_INIT_VALUE or previous
774 unsigned long *tptr = (unsigned long *) tmp;
776 /* in case the beginning of the buffer isn't aligned */
777 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
778 nbytes -= (pend - pdata);
780 CRC_INNER_LOOP(32, crc, *pdata++);
782 /* handle bulk of data as 32-bit words */
783 pend = pdata + (nbytes & 0xfffffffc);
784 while (pdata < pend) {
785 *tptr = *(unsigned long *) pdata;
786 pdata += sizeof(unsigned long *);
787 CRC_INNER_LOOP(32, crc, tmp[0]);
788 CRC_INNER_LOOP(32, crc, tmp[1]);
789 CRC_INNER_LOOP(32, crc, tmp[2]);
790 CRC_INNER_LOOP(32, crc, tmp[3]);
793 /* 1-3 bytes at end of buffer */
794 pend = pdata + (nbytes & 0x03);
796 CRC_INNER_LOOP(32, crc, *pdata++);
798 pend = pdata + nbytes;
800 CRC_INNER_LOOP(32, crc, *pdata++);
801 #endif /* __mips__ */
806 * Traverse a string of 1-byte tag/1-byte length/variable-length value
807 * triples, returning a pointer to the substring whose first element
810 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
815 elt = (bcm_tlv_t *) buf;
818 /* find tagged parameter */
819 while (totlen >= 2) {
822 /* validate remaining totlen */
823 if ((elt->id == key) && (totlen >= (len + 2)))
826 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
836 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
841 int slen = 0, nlen = 0;
850 for (i = 0; flags != 0; i++) {
853 if (bit == 0 && flags != 0) {
854 /* print any unnamed bits */
855 snprintf(hexstr, 16, "0x%X", flags);
857 flags = 0; /* exit loop */
858 } else if ((flags & bit) == 0)
863 /* count btwn flag space */
866 /* need NULL char as well */
869 /* copy NULL char but don't count it */
870 strncpy(p, name, nlen + 1);
872 /* copy btwn flag space and NULL char */
874 p += snprintf(p, 2, " ");
878 /* indicate the str was too short */
881 p -= 2 - len; /* overwrite last char */
882 p += snprintf(p, 2, ">");
885 return (int)(p - buf);
888 /* print bytes formatted as hex to a string. return the resulting string length */
889 int bcm_format_hex(char *str, const void *bytes, int len)
893 const u8 *src = (const u8 *)bytes;
895 for (i = 0; i < len; i++) {
896 p += snprintf(p, 3, "%02X", *src);
899 return (int)(p - str);
901 #endif /* defined(BCMDBG) */
903 /* pretty hex print a contiguous buffer */
904 void prhex(const char *msg, unsigned char *buf, uint nbytes)
907 int len = sizeof(line);
911 if (msg && (msg[0] != '\0'))
912 printk(KERN_DEBUG "%s:\n", msg);
915 for (i = 0; i < nbytes; i++) {
917 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
922 nchar = snprintf(p, len, "%02x ", buf[i]);
928 printk(KERN_DEBUG "%s\n", line); /* flush line */
934 /* flush last partial line */
936 printk(KERN_DEBUG "%s\n", line);
939 char *bcm_chipname(uint chipid, char *buf, uint len)
943 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
944 snprintf(buf, len, fmt, chipid);
948 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
952 len = strlen(name) + 1;
954 if ((len + datalen) > buflen)
957 strncpy(buf, name, buflen);
959 /* append data onto the end of the name string */
960 memcpy(&buf[len], data, datalen);
966 /* Quarter dBm units to mW
967 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
968 * Table is offset so the last entry is largest mW value that fits in
972 #define QDBM_OFFSET 153 /* Offset for first entry */
973 #define QDBM_TABLE_LEN 40 /* Table size */
975 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
976 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
978 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
980 /* Largest mW value that will round down to the last table entry,
981 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
982 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
983 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
985 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
987 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
988 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
989 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
990 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
991 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
992 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
993 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
996 u16 bcm_qdbm_to_mw(u8 qdbm)
999 int idx = qdbm - QDBM_OFFSET;
1001 if (idx >= QDBM_TABLE_LEN) {
1002 /* clamp to max u16 mW value */
1006 /* scale the qdBm index up to the range of the table 0-40
1007 * where an offset of 40 qdBm equals a factor of 10 mW.
1014 /* return the mW value scaled down to the correct factor of 10,
1015 * adding in factor/2 to get proper rounding.
1017 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
1019 u8 bcm_mw_to_qdbm(u16 mw)
1026 /* handle boundary case */
1030 offset = QDBM_OFFSET;
1032 /* move mw into the range of the table */
1033 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1038 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1039 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1040 nqdBm_to_mW_map[qdbm]) / 2;
1041 if (mw_uint < boundary)
1045 qdbm += (u8) offset;
1049 uint bcm_bitcount(u8 *bitmap, uint length)
1051 uint bitcount = 0, i;
1053 for (i = 0; i < length; i++) {
1062 /* Initialization of bcmstrbuf structure */
1063 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1065 b->origsize = b->size = size;
1066 b->origbuf = b->buf = buf;
1069 /* Buffer sprintf wrapper to guard against buffer overflow */
1070 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1076 r = vsnprintf(b->buf, b->size, fmt, ap);
1078 /* Non Ansi C99 compliant returns -1,
1079 * Ansi compliant return r >= b->size,
1080 * bcmstdlib returns 0, handle all
1082 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {