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>
20 #include <linux/module.h>
21 #include <linux/pci.h>
22 #include <linux/netdevice.h>
23 #include <linux/sched.h>
29 #include <proto/802.11.h>
31 /* Global ASSERT type flag */
34 struct sk_buff *BCMFASTPATH pkt_buf_get_skb(uint len)
38 skb = dev_alloc_skb(len);
47 /* Free the driver packet. Free the tag if present */
48 void BCMFASTPATH pkt_buf_free_skb(struct sk_buff *skb)
55 /* perversion: we use skb->next to chain multi-skb packets */
61 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
64 dev_kfree_skb_any(skb);
66 /* can free immediately (even in_irq()) if destructor
76 /* copy a buffer into a pkt buffer chain */
77 uint pktfrombuf(struct sk_buff *p, uint offset, int len,
82 /* skip 'offset' bytes */
83 for (; p && offset; p = p->next) {
84 if (offset < (uint) (p->len))
93 for (; p && len; p = p->next) {
94 n = min((uint) (p->len) - offset, (uint) len);
95 memcpy(p->data + offset, buf, n);
104 /* return total length of buffer chain */
105 uint BCMFASTPATH pkttotlen(struct sk_buff *p)
110 for (; p; p = p->next)
116 * osl multiple-precedence packet queue
117 * hi_prec is always >= the number of the highest non-empty precedence
119 struct sk_buff *BCMFASTPATH pktq_penq(struct pktq *pq, int prec,
124 ASSERT(prec >= 0 && prec < pq->num_prec);
125 ASSERT(p->prev == NULL); /* queueing chains not allowed */
127 ASSERT(!pktq_full(pq));
128 ASSERT(!pktq_pfull(pq, prec));
142 if (pq->hi_prec < prec)
143 pq->hi_prec = (u8) prec;
148 struct sk_buff *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec,
153 ASSERT(prec >= 0 && prec < pq->num_prec);
154 ASSERT(p->prev == NULL); /* queueing chains not allowed */
156 ASSERT(!pktq_full(pq));
157 ASSERT(!pktq_pfull(pq, prec));
170 if (pq->hi_prec < prec)
171 pq->hi_prec = (u8) prec;
176 struct sk_buff *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
181 ASSERT(prec >= 0 && prec < pq->num_prec);
202 struct sk_buff *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
205 struct sk_buff *p, *prev;
207 ASSERT(prec >= 0 && prec < pq->num_prec);
215 for (prev = NULL; p != q->tail; p = p->prev)
232 void pktq_pflush(struct pktq *pq, int prec, bool dir)
251 void pktq_flush(struct pktq *pq, bool dir)
254 for (prec = 0; prec < pq->num_prec; prec++)
255 pktq_pflush(pq, prec, dir);
256 ASSERT(pq->len == 0);
258 #else /* !BRCM_FULLMAC */
260 pktq_pflush(struct pktq *pq, int prec, bool dir,
261 ifpkt_cb_t fn, int arg)
264 struct sk_buff *p, *prev = NULL;
269 if (fn == NULL || (*fn) (p, arg)) {
270 bool head = (p == q->head);
274 prev->prev = p->prev;
279 p = (head ? q->head : prev->prev);
286 if (q->head == NULL) {
292 void pktq_flush(struct pktq *pq, bool dir,
293 ifpkt_cb_t fn, int arg)
296 for (prec = 0; prec < pq->num_prec; prec++)
297 pktq_pflush(pq, prec, dir, fn, arg);
299 ASSERT(pq->len == 0);
301 #endif /* BRCM_FULLMAC */
303 void pktq_init(struct pktq *pq, int num_prec, int max_len)
307 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
309 /* pq is variable size; only zero out what's requested */
311 offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
313 pq->num_prec = (u16) num_prec;
315 pq->max = (u16) max_len;
317 for (prec = 0; prec < num_prec; prec++)
318 pq->q[prec].max = pq->max;
321 struct sk_buff *pktq_peek_tail(struct pktq *pq, int *prec_out)
328 for (prec = 0; prec < pq->hi_prec; prec++)
329 if (pq->q[prec].head)
335 return pq->q[prec].tail;
338 /* Return sum of lengths of a specific set of precedences */
339 int pktq_mlen(struct pktq *pq, uint prec_bmp)
345 for (prec = 0; prec <= pq->hi_prec; prec++)
346 if (prec_bmp & (1 << prec))
347 len += pq->q[prec].len;
351 /* Priority dequeue from a specific set of precedences */
352 struct sk_buff *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp,
362 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
365 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
391 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
392 int bcm_ether_atoe(char *p, u8 *ea)
397 ea[i++] = (char)simple_strtoul(p, &p, 16);
406 * Search the name=value vars for a specific one and return its value.
407 * Returns NULL if not found.
409 char *getvar(char *vars, const char *name)
421 /* first look in vars[] */
422 for (s = vars; s && *s;) {
423 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
432 /* then query nvram */
433 return nvram_get(name);
438 * Search the vars for a specific one and return its value as
439 * an integer. Returns 0 if not found.
441 int getintvar(char *vars, const char *name)
445 val = getvar(vars, name);
449 return simple_strtoul(val, NULL, 0);
453 /* pretty hex print a pkt buffer chain */
454 void prpkt(const char *msg, struct sk_buff *p0)
458 if (msg && (msg[0] != '\0'))
459 printk(KERN_DEBUG "%s:\n", msg);
461 for (p = p0; p; p = p->next)
462 prhex(NULL, p->data, p->len);
464 #endif /* defined(BCMDBG) */
466 /* iovar table lookup */
467 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
469 const bcm_iovar_t *vi;
470 const char *lookup_name;
472 /* skip any ':' delimited option prefixes */
473 lookup_name = strrchr(name, ':');
474 if (lookup_name != NULL)
479 ASSERT(table != NULL);
481 for (vi = table; vi->name; vi++) {
482 if (!strcmp(vi->name, lookup_name))
485 /* ran to end of table */
487 return NULL; /* var name not found */
490 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
494 /* length check on io buf */
503 /* all integers are s32 sized args at the ioctl interface */
504 if (len < (int)sizeof(int)) {
505 bcmerror = -BCME_BUFTOOSHORT;
510 /* buffer must meet minimum length requirement */
511 if (len < vi->minlen) {
512 bcmerror = -BCME_BUFTOOSHORT;
518 /* Cannot return nil... */
519 bcmerror = -BCME_UNSUPPORTED;
521 /* Set is an action w/o parameters */
522 bcmerror = -BCME_BUFTOOLONG;
527 /* unknown type for length check in iovar info */
529 bcmerror = -BCME_UNSUPPORTED;
535 /*******************************************************************************
538 * Computes a crc8 over the input data using the polynomial:
540 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
542 * The caller provides the initial value (either CRC8_INIT_VALUE
543 * or the previous returned value) to allow for processing of
544 * discontiguous blocks of data. When generating the CRC the
545 * caller is responsible for complementing the final return value
546 * and inserting it into the byte stream. When checking, a final
547 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
549 * Reference: Dallas Semiconductor Application Note 27
550 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
551 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
552 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
554 * ****************************************************************************
557 static const u8 crc8_table[256] = {
558 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
559 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
560 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
561 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
562 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
563 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
564 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
565 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
566 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
567 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
568 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
569 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
570 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
571 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
572 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
573 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
574 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
575 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
576 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
577 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
578 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
579 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
580 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
581 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
582 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
583 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
584 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
585 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
586 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
587 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
588 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
589 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
592 #define CRC_INNER_LOOP(n, c, x) \
593 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
595 u8 hndcrc8(u8 *pdata, /* pointer to array of data to process */
596 uint nbytes, /* number of input data bytes to process */
597 u8 crc /* either CRC8_INIT_VALUE or previous return value */
599 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
600 * to avoid the undefined and unnecessary (u8 >> 8) operation.
603 crc = crc8_table[(crc ^ *pdata++) & 0xff];
608 /*******************************************************************************
611 * Computes a crc16 over the input data using the polynomial:
613 * x^16 + x^12 +x^5 + 1
615 * The caller provides the initial value (either CRC16_INIT_VALUE
616 * or the previous returned value) to allow for processing of
617 * discontiguous blocks of data. When generating the CRC the
618 * caller is responsible for complementing the final return value
619 * and inserting it into the byte stream. When checking, a final
620 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
622 * Reference: Dallas Semiconductor Application Note 27
623 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
624 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
625 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
627 * ****************************************************************************
630 static const u16 crc16_table[256] = {
631 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
632 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
633 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
634 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
635 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
636 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
637 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
638 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
639 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
640 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
641 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
642 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
643 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
644 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
645 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
646 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
647 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
648 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
649 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
650 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
651 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
652 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
653 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
654 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
655 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
656 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
657 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
658 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
659 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
660 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
661 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
662 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
665 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
666 uint nbytes, /* number of input data bytes to process */
667 u16 crc /* either CRC16_INIT_VALUE or previous return value */
670 CRC_INNER_LOOP(16, crc, *pdata++);
674 static const u32 crc32_table[256] = {
675 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
676 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
677 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
678 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
679 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
680 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
681 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
682 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
683 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
684 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
685 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
686 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
687 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
688 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
689 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
690 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
691 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
692 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
693 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
694 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
695 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
696 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
697 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
698 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
699 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
700 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
701 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
702 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
703 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
704 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
705 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
706 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
707 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
708 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
709 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
710 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
711 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
712 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
713 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
714 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
715 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
716 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
717 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
718 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
719 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
720 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
721 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
722 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
723 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
724 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
725 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
726 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
727 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
728 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
729 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
730 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
731 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
732 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
733 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
734 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
735 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
736 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
737 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
738 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
741 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
742 uint nbytes, /* number of input data bytes to process */
743 u32 crc /* either CRC32_INIT_VALUE or previous
750 unsigned long *tptr = (unsigned long *) tmp;
752 /* in case the beginning of the buffer isn't aligned */
753 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
754 nbytes -= (pend - pdata);
756 CRC_INNER_LOOP(32, crc, *pdata++);
758 /* handle bulk of data as 32-bit words */
759 pend = pdata + (nbytes & 0xfffffffc);
760 while (pdata < pend) {
761 *tptr = *(unsigned long *) pdata;
762 pdata += sizeof(unsigned long *);
763 CRC_INNER_LOOP(32, crc, tmp[0]);
764 CRC_INNER_LOOP(32, crc, tmp[1]);
765 CRC_INNER_LOOP(32, crc, tmp[2]);
766 CRC_INNER_LOOP(32, crc, tmp[3]);
769 /* 1-3 bytes at end of buffer */
770 pend = pdata + (nbytes & 0x03);
772 CRC_INNER_LOOP(32, crc, *pdata++);
774 pend = pdata + nbytes;
776 CRC_INNER_LOOP(32, crc, *pdata++);
777 #endif /* __mips__ */
782 * Traverse a string of 1-byte tag/1-byte length/variable-length value
783 * triples, returning a pointer to the substring whose first element
786 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
791 elt = (bcm_tlv_t *) buf;
794 /* find tagged parameter */
795 while (totlen >= 2) {
798 /* validate remaining totlen */
799 if ((elt->id == key) && (totlen >= (len + 2)))
802 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
812 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
817 int slen = 0, nlen = 0;
826 for (i = 0; flags != 0; i++) {
829 if (bit == 0 && flags != 0) {
830 /* print any unnamed bits */
831 snprintf(hexstr, 16, "0x%X", flags);
833 flags = 0; /* exit loop */
834 } else if ((flags & bit) == 0)
839 /* count btwn flag space */
842 /* need NULL char as well */
845 /* copy NULL char but don't count it */
846 strncpy(p, name, nlen + 1);
848 /* copy btwn flag space and NULL char */
850 p += snprintf(p, 2, " ");
854 /* indicate the str was too short */
857 p -= 2 - len; /* overwrite last char */
858 p += snprintf(p, 2, ">");
861 return (int)(p - buf);
864 /* print bytes formatted as hex to a string. return the resulting string length */
865 int bcm_format_hex(char *str, const void *bytes, int len)
869 const u8 *src = (const u8 *)bytes;
871 for (i = 0; i < len; i++) {
872 p += snprintf(p, 3, "%02X", *src);
875 return (int)(p - str);
877 #endif /* defined(BCMDBG) */
879 /* pretty hex print a contiguous buffer */
880 void prhex(const char *msg, unsigned char *buf, uint nbytes)
883 int len = sizeof(line);
887 if (msg && (msg[0] != '\0'))
888 printk(KERN_DEBUG "%s:\n", msg);
891 for (i = 0; i < nbytes; i++) {
893 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
898 nchar = snprintf(p, len, "%02x ", buf[i]);
904 printk(KERN_DEBUG "%s\n", line); /* flush line */
910 /* flush last partial line */
912 printk(KERN_DEBUG "%s\n", line);
915 char *bcm_chipname(uint chipid, char *buf, uint len)
919 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
920 snprintf(buf, len, fmt, chipid);
924 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
928 len = strlen(name) + 1;
930 if ((len + datalen) > buflen)
933 strncpy(buf, name, buflen);
935 /* append data onto the end of the name string */
936 memcpy(&buf[len], data, datalen);
942 /* Quarter dBm units to mW
943 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
944 * Table is offset so the last entry is largest mW value that fits in
948 #define QDBM_OFFSET 153 /* Offset for first entry */
949 #define QDBM_TABLE_LEN 40 /* Table size */
951 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
952 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
954 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
956 /* Largest mW value that will round down to the last table entry,
957 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
958 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
959 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
961 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
963 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
964 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
965 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
966 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
967 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
968 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
969 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
972 u16 bcm_qdbm_to_mw(u8 qdbm)
975 int idx = qdbm - QDBM_OFFSET;
977 if (idx >= QDBM_TABLE_LEN) {
978 /* clamp to max u16 mW value */
982 /* scale the qdBm index up to the range of the table 0-40
983 * where an offset of 40 qdBm equals a factor of 10 mW.
990 /* return the mW value scaled down to the correct factor of 10,
991 * adding in factor/2 to get proper rounding.
993 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
995 u8 bcm_mw_to_qdbm(u16 mw)
1002 /* handle boundary case */
1006 offset = QDBM_OFFSET;
1008 /* move mw into the range of the table */
1009 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1014 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1015 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1016 nqdBm_to_mW_map[qdbm]) / 2;
1017 if (mw_uint < boundary)
1021 qdbm += (u8) offset;
1025 uint bcm_bitcount(u8 *bitmap, uint length)
1027 uint bitcount = 0, i;
1029 for (i = 0; i < length; i++) {
1038 /* Initialization of bcmstrbuf structure */
1039 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1041 b->origsize = b->size = size;
1042 b->origbuf = b->buf = buf;
1045 /* Buffer sprintf wrapper to guard against buffer overflow */
1046 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1052 r = vsnprintf(b->buf, b->size, fmt, ap);
1054 /* Non Ansi C99 compliant returns -1,
1055 * Ansi compliant return r >= b->size,
1056 * bcmstdlib returns 0, handle all
1058 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1070 #if defined(BCMDBG_ASSERT)
1071 void osl_assert(char *exp, char *file, int line)
1076 basename = strrchr(file, '/');
1084 snprintf(tempbuf, 256,
1085 "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
1089 * Print assert message and give it time to
1090 * be written to /var/log/messages
1092 if (!in_interrupt()) {
1093 const int delay = 3;
1094 printk(KERN_ERR "%s", tempbuf);
1095 printk(KERN_ERR "panic in %d seconds\n", delay);
1096 set_current_state(TASK_INTERRUPTIBLE);
1097 schedule_timeout(delay * HZ);
1100 switch (g_assert_type) {
1102 panic(KERN_ERR "%s", tempbuf);
1105 printk(KERN_ERR "%s", tempbuf);
1109 printk(KERN_ERR "%s", tempbuf);
1115 #endif /* defined(BCMDBG_ASSERT) */