2 * Driver O/S-independent utility routines
4 * Copyright (C) 2009, Broadcom Corporation
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 * $Id: bcmutils.c,v 1.218.2.19 2009/11/11 18:22:21 Exp $
26 #endif /* BCMDRIVER */
27 #if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || defined(_CFE_) || \
30 #include <bcmstdlib.h>
32 #include <bcmendian.h>
34 #include <proto/ethernet.h>
35 #include <proto/vlan.h>
36 #include <proto/bcmip.h>
37 #include <proto/802.1d.h>
45 /* nvram vars cache */
46 static char *nvram_vars
= NULL
;
47 static int vars_len
= -1;
50 /* copy a pkt buffer chain into a buffer */
52 pktcopy(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
57 len
= 4096; /* "infinite" */
59 /* skip 'offset' bytes */
60 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
61 if (offset
< (uint
)PKTLEN(osh
, p
))
63 offset
-= PKTLEN(osh
, p
);
70 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
71 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
72 bcopy(PKTDATA(osh
, p
) + offset
, buf
, n
);
82 /* copy a buffer into a pkt buffer chain */
84 pktfrombuf(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
88 /* skip 'offset' bytes */
89 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
90 if (offset
< (uint
)PKTLEN(osh
, p
))
92 offset
-= PKTLEN(osh
, p
);
99 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
100 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
101 bcopy(buf
, PKTDATA(osh
, p
) + offset
, n
);
112 /* copy data from one pkt buffer (chain) to another */
114 pkt2pktcopy(osl_t
*osh
, void *p1
, uint offs1
, void *p2
, uint offs2
, int maxlen
)
117 uint len1
, len2
, copylen
, totallen
;
119 for (; p1
&& offs
; p1
= PKTNEXT(osh
, p1
)) {
120 if (offs1
< (uint
)PKTLEN(osh
, p1
))
122 offs1
-= PKTLEN(osh
, p1
);
124 for (; p2
&& offs
; p2
= PKTNEXT(osh
, p2
)) {
125 if (offs2
< (uint
)PKTLEN(osh
, p2
))
127 offs2
-= PKTLEN(osh
, p2
);
130 /* Heck w/it, only need the above for now */
135 /* return total length of buffer chain */
137 pkttotlen(osl_t
*osh
, void *p
)
142 for (; p
; p
= PKTNEXT(osh
, p
))
143 total
+= PKTLEN(osh
, p
);
147 /* return the last buffer of chained pkt */
149 pktlast(osl_t
*osh
, void *p
)
151 for (; PKTNEXT(osh
, p
); p
= PKTNEXT(osh
, p
))
157 /* count segments of a chained packet */
159 pktsegcnt(osl_t
*osh
, void *p
)
163 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
))
171 * osl multiple-precedence packet queue
172 * hi_prec is always >= the number of the highest non-empty precedence
175 pktq_penq(struct pktq
*pq
, int prec
, void *p
)
179 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
180 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
182 ASSERT(!pktq_full(pq
));
183 ASSERT(!pktq_pfull(pq
, prec
));
188 PKTSETLINK(q
->tail
, p
);
197 if (pq
->hi_prec
< prec
)
198 pq
->hi_prec
= (uint8
)prec
;
204 pktq_penq_head(struct pktq
*pq
, int prec
, void *p
)
208 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
209 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
211 ASSERT(!pktq_full(pq
));
212 ASSERT(!pktq_pfull(pq
, prec
));
219 PKTSETLINK(p
, q
->head
);
225 if (pq
->hi_prec
< prec
)
226 pq
->hi_prec
= (uint8
)prec
;
232 pktq_pdeq(struct pktq
*pq
, int prec
)
237 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
241 if ((p
= q
->head
) == NULL
)
244 if ((q
->head
= PKTLINK(p
)) == NULL
)
257 pktq_pdeq_tail(struct pktq
*pq
, int prec
)
262 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
266 if ((p
= q
->head
) == NULL
)
269 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
273 PKTSETLINK(prev
, NULL
);
286 pktq_pflush(osl_t
*osh
, struct pktq
*pq
, int prec
, bool dir
)
294 q
->head
= PKTLINK(p
);
296 PKTFREE(osh
, p
, dir
);
306 pktq_pdel(struct pktq
*pq
, void *pktbuf
, int prec
)
311 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
318 if (q
->head
== pktbuf
) {
319 if ((q
->head
= PKTLINK(pktbuf
)) == NULL
)
322 for (p
= q
->head
; p
&& PKTLINK(p
) != pktbuf
; p
= PKTLINK(p
))
327 PKTSETLINK(p
, PKTLINK(pktbuf
));
328 if (q
->tail
== pktbuf
)
334 PKTSETLINK(pktbuf
, NULL
);
339 pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
343 ASSERT(num_prec
> 0 && num_prec
<= PKTQ_MAX_PREC
);
345 /* pq is variable size; only zero out what's requested */
346 bzero(pq
, OFFSETOF(struct pktq
, q
) + (sizeof(struct pktq_prec
) * num_prec
));
348 pq
->num_prec
= (uint16
)num_prec
;
350 pq
->max
= (uint16
)max_len
;
352 for (prec
= 0; prec
< num_prec
; prec
++)
353 pq
->q
[prec
].max
= pq
->max
;
357 pktq_deq(struct pktq
*pq
, int *prec_out
)
366 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
371 if ((p
= q
->head
) == NULL
)
374 if ((q
->head
= PKTLINK(p
)) == NULL
)
390 pktq_deq_tail(struct pktq
*pq
, int *prec_out
)
399 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
400 if (pq
->q
[prec
].head
)
405 if ((p
= q
->head
) == NULL
)
408 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
412 PKTSETLINK(prev
, NULL
);
430 pktq_peek(struct pktq
*pq
, int *prec_out
)
437 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
443 return (pq
->q
[prec
].head
);
447 pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
454 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
455 if (pq
->q
[prec
].head
)
461 return (pq
->q
[prec
].tail
);
465 pktq_flush(osl_t
*osh
, struct pktq
*pq
, bool dir
)
468 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
469 pktq_pflush(osh
, pq
, prec
, dir
);
470 ASSERT(pq
->len
== 0);
473 /* Return sum of lengths of a specific set of precedences */
475 pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
481 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
482 if (prec_bmp
& (1 << prec
))
483 len
+= pq
->q
[prec
].len
;
488 /* Priority dequeue from a specific set of precedences */
490 pktq_mdeq(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
499 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
502 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
508 if ((p
= q
->head
) == NULL
)
511 if ((q
->head
= PKTLINK(p
)) == NULL
)
525 #endif /* BCMDRIVER */
528 const unsigned char bcm_ctype
[] = {
529 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 0-7 */
530 _BCM_C
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
,
532 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 16-23 */
533 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 24-31 */
534 _BCM_S
|_BCM_SP
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 32-39 */
535 _BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 40-47 */
536 _BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
, /* 48-55 */
537 _BCM_D
,_BCM_D
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 56-63 */
538 _BCM_P
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
,
539 _BCM_U
|_BCM_X
, _BCM_U
, /* 64-71 */
540 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 72-79 */
541 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 80-87 */
542 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 88-95 */
543 _BCM_P
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
,
544 _BCM_L
|_BCM_X
, _BCM_L
, /* 96-103 */
545 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 104-111 */
546 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 112-119 */
547 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_C
, /* 120-127 */
548 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
549 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
550 _BCM_S
|_BCM_SP
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
551 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 160-175 */
552 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
553 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 176-191 */
554 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
,
555 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, /* 192-207 */
556 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_P
, _BCM_U
, _BCM_U
, _BCM_U
,
557 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_L
, /* 208-223 */
558 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
,
559 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, /* 224-239 */
560 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_P
, _BCM_L
, _BCM_L
, _BCM_L
,
561 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
/* 240-255 */
565 BCMROMFN(bcm_strtoul
)(char *cp
, char **endp
, uint base
)
567 ulong result
, last_result
= 0, value
;
572 while (bcm_isspace(*cp
))
577 else if (cp
[0] == '-') {
584 if ((cp
[1] == 'x') || (cp
[1] == 'X')) {
593 } else if (base
== 16 && (cp
[0] == '0') && ((cp
[1] == 'x') || (cp
[1] == 'X'))) {
599 while (bcm_isxdigit(*cp
) &&
600 (value
= bcm_isdigit(*cp
) ? *cp
-'0' : bcm_toupper(*cp
)-'A'+10) < base
) {
601 result
= result
*base
+ value
;
602 /* Detected overflow */
603 if (result
< last_result
&& !minus
)
604 return ((unsigned long) -1);
605 last_result
= result
;
610 result
= (ulong
)(result
* -1);
619 BCMROMFN(bcm_atoi
)(char *s
)
621 return (int)bcm_strtoul(s
, NULL
, 10);
624 /* return pointer to location of substring 'needle' in 'haystack' */
626 BCMROMFN(bcmstrstr
)(char *haystack
, char *needle
)
631 if ((haystack
== NULL
) || (needle
== NULL
))
634 nlen
= strlen(needle
);
635 len
= strlen(haystack
) - nlen
+ 1;
637 for (i
= 0; i
< len
; i
++)
638 if (memcmp(needle
, &haystack
[i
], nlen
) == 0)
639 return (&haystack
[i
]);
644 BCMROMFN(bcmstrcat
)(char *dest
, const char *src
)
648 p
= dest
+ strlen(dest
);
650 while ((*p
++ = *src
++) != '\0')
657 BCMROMFN(bcmstrncat
)(char *dest
, const char *src
, uint size
)
662 p
= dest
+ strlen(dest
);
665 while (p
!= endp
&& (*p
++ = *src
++) != '\0')
671 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
673 BCMROMFN(bcm_ether_atoe
)(char *p
, struct ether_addr
*ea
)
678 ea
->octet
[i
++] = (char) bcm_strtoul(p
, &p
, 16);
686 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
687 /* registry routine buffer preparation utility functions:
688 * parameter order is like strncpy, but returns count
689 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
705 /* wbuflen is in bytes */
706 wbuflen
/= sizeof(ushort
);
708 for (i
= 0; i
< wbuflen
; ++i
) {
711 *abuf
++ = (char) *wbuf
++;
718 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
721 bcm_ether_ntoa(const struct ether_addr
*ea
, char *buf
)
723 static const char template[] = "%02x:%02x:%02x:%02x:%02x:%02x";
724 snprintf(buf
, 18, template,
725 ea
->octet
[0]&0xff, ea
->octet
[1]&0xff, ea
->octet
[2]&0xff,
726 ea
->octet
[3]&0xff, ea
->octet
[4]&0xff, ea
->octet
[5]&0xff);
731 bcm_ip_ntoa(struct ipv4_addr
*ia
, char *buf
)
733 snprintf(buf
, 16, "%d.%d.%d.%d",
734 ia
->addr
[0], ia
->addr
[1], ia
->addr
[2], ia
->addr
[3]);
745 for (i
= 0; i
< ms
; i
++) {
751 * Search the name=value vars for a specific one and return its value.
752 * Returns NULL if not found.
755 getvar(char *vars
, const char *name
)
770 /* first look in vars[] */
771 for (s
= vars
; s
&& *s
;) {
772 if ((bcmp(s
, name
, len
) == 0) && (s
[len
] == '='))
779 /* then query nvram */
780 return (nvram_get(name
));
781 #endif /* defined(_MINOSL_) */
785 * Search the vars for a specific one and return its value as
786 * an integer. Returns 0 if not found.
789 getintvar(char *vars
, const char *name
)
796 if ((val
= getvar(vars
, name
)) == NULL
)
799 return (bcm_strtoul(val
, NULL
, 0));
800 #endif /* _MINOSL_ */
804 /* Search for token in comma separated token-string */
806 findmatch(char *string
, char *name
)
812 while ((c
= strchr(string
, ',')) != NULL
) {
813 if (len
== (uint
)(c
- string
) && !strncmp(string
, name
, len
))
818 return (!strcmp(string
, name
));
821 /* Return gpio pin number assigned to the named pin
823 * Variable should be in format:
825 * gpio<N>=pin_name,pin_name
827 * This format allows multiple features to share the gpio with mutual
830 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
831 * and if def_pin is not used by others.
834 getgpiopin(char *vars
, char *pin_name
, uint def_pin
)
836 char name
[] = "gpioXXXX";
840 /* Go thru all possibilities till a match in pin name */
841 for (pin
= 0; pin
< GPIO_NUMPINS
; pin
++) {
842 snprintf(name
, sizeof(name
), "gpio%d", pin
);
843 val
= getvar(vars
, name
);
844 if (val
&& findmatch(val
, pin_name
))
848 if (def_pin
!= GPIO_PIN_NOTDEFINED
) {
849 /* make sure the default pin is not used by someone else */
850 snprintf(name
, sizeof(name
), "gpio%d", def_pin
);
851 if (getvar(vars
, name
)) {
852 def_pin
= GPIO_PIN_NOTDEFINED
;
859 #if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
861 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
869 /* last entry logged */
870 static uint logi
= 0;
871 /* next entry to read */
872 static uint readi
= 0;
873 #endif /* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */
879 BCMPERF_ENABLE_INSTRCOUNT();
880 BCMPERF_ENABLE_ICACHE_MISS();
881 BCMPERF_ENABLE_ICACHE_HIT();
885 bcmlog(char *fmt
, uint a1
, uint a2
)
887 static uint last
= 0;
889 OSL_GETCYCLES(cycles
);
893 logtab
[i
].cycles
= cycles
- last
;
898 logi
= (i
+ 1) % LOGSIZE
;
906 static uint last
= 0;
907 static uint32 ic_miss
= 0;
908 static uint32 instr_count
= 0;
910 uint32 instr_count_cur
;
913 OSL_GETCYCLES(cycles
);
914 BCMPERF_GETICACHE_MISS(ic_miss_cur
);
915 BCMPERF_GETINSTRCOUNT(instr_count_cur
);
919 logtab
[i
].cycles
= cycles
- last
;
920 logtab
[i
].a1
= ic_miss_cur
- ic_miss
;
921 logtab
[i
].a2
= instr_count_cur
- instr_count
;
924 logi
= (i
+ 1) % LOGSIZE
;
927 instr_count
= instr_count_cur
;
928 ic_miss
= ic_miss_cur
;
933 bcmdumplog(char *buf
, int size
)
939 limit
= buf
+ size
- 80;
947 /* print in chronological order */
949 for (j
= 0; j
< num
&& (buf
< limit
); readi
= (readi
+ 1) % LOGSIZE
, j
++) {
950 if (logtab
[readi
].fmt
== NULL
)
953 buf
+= snprintf(buf
, (limit
- buf
), "%d\t", logtab
[readi
].cycles
);
954 buf
+= snprintf(buf
, (limit
- buf
), logtab
[readi
].fmt
,
955 logtab
[readi
].a1
, logtab
[readi
].a2
);
956 buf
+= snprintf(buf
, (limit
- buf
), "\n");
963 * Dump one log entry at a time.
964 * Return index of next entry or -1 when no more .
967 bcmdumplogent(char *buf
, uint i
)
972 * If buf is NULL, return the starting index,
973 * interpreting i as the indicator of last 'i' entries to dump.
976 i
= ((i
> 0) && (i
< (LOGSIZE
- 1))) ? i
: (LOGSIZE
- 1);
977 return ((logi
- i
) % LOGSIZE
);
988 for (; (i
!= logi
) && !hit
; i
= (i
+ 1) % LOGSIZE
) {
989 if (logtab
[i
].fmt
== NULL
)
991 buf
+= sprintf(buf
, "%d: %d\t", i
, logtab
[i
].cycles
);
992 buf
+= sprintf(buf
, logtab
[i
].fmt
, logtab
[i
].a1
, logtab
[i
].a2
);
993 buf
+= sprintf(buf
, "\n");
1000 #endif /* BCMPERFSTATS */
1002 #if defined(BCMTSTAMPEDLOGS)
1003 /* Store a TSF timestamp and a log line in the log buffer */
1005 bcmtslog(uint32 tstamp
, char *fmt
, uint a1
, uint a2
)
1009 logtab
[i
].cycles
= tstamp
;
1010 logtab
[i
].fmt
= fmt
;
1014 logi
= (i
+ 1) % LOGSIZE
;
1017 /* Print out a microsecond timestamp as "sec.ms.us " */
1019 bcmprinttstamp(uint32 ticks
)
1023 us
= (ticks
% TSF_TICKS_PER_MS
) * 1000 / TSF_TICKS_PER_MS
;
1024 ms
= ticks
/ TSF_TICKS_PER_MS
;
1027 printf("%04u.%03u.%03u ", sec
, ms
, us
);
1030 /* Print out the log buffer with timestamps */
1032 bcmprinttslogs(void)
1041 /* Format and print the log entries directly in chronological order */
1042 for (j
= 0; j
< num
; readi
= (readi
+ 1) % LOGSIZE
, j
++) {
1043 if (logtab
[readi
].fmt
== NULL
)
1045 bcmprinttstamp(logtab
[readi
].cycles
);
1046 printf(logtab
[readi
].fmt
, logtab
[readi
].a1
, logtab
[readi
].a2
);
1050 #endif /* BCMTSTAMPEDLOGS */
1053 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
1054 * Also updates the inplace vlan tag if requested.
1055 * For debugging, it returns an indication of what it did.
1058 pktsetprio(void *pkt
, bool update_vtag
)
1060 struct ether_header
*eh
;
1061 struct ethervlan_header
*evh
;
1066 pktdata
= (uint8
*) PKTDATA(NULL
, pkt
);
1067 ASSERT(ISALIGNED((uintptr
)pktdata
, sizeof(uint16
)));
1069 eh
= (struct ether_header
*) pktdata
;
1071 if (ntoh16(eh
->ether_type
) == ETHER_TYPE_8021Q
) {
1073 int vlan_prio
, dscp_prio
= 0;
1075 evh
= (struct ethervlan_header
*)eh
;
1077 vlan_tag
= ntoh16(evh
->vlan_tag
);
1078 vlan_prio
= (int) (vlan_tag
>> VLAN_PRI_SHIFT
) & VLAN_PRI_MASK
;
1080 if (ntoh16(evh
->ether_type
) == ETHER_TYPE_IP
) {
1081 uint8
*ip_body
= pktdata
+ sizeof(struct ethervlan_header
);
1082 uint8 tos_tc
= IP_TOS46(ip_body
);
1083 dscp_prio
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
1086 /* DSCP priority gets precedence over 802.1P (vlan tag) */
1087 if (dscp_prio
!= 0) {
1088 priority
= dscp_prio
;
1089 rc
|= PKTPRIO_VDSCP
;
1091 priority
= vlan_prio
;
1095 * If the DSCP priority is not the same as the VLAN priority,
1096 * then overwrite the priority field in the vlan tag, with the
1097 * DSCP priority value. This is required for Linux APs because
1098 * the VLAN driver on Linux, overwrites the skb->priority field
1099 * with the priority value in the vlan tag
1101 if (update_vtag
&& (priority
!= vlan_prio
)) {
1102 vlan_tag
&= ~(VLAN_PRI_MASK
<< VLAN_PRI_SHIFT
);
1103 vlan_tag
|= (uint16
)priority
<< VLAN_PRI_SHIFT
;
1104 evh
->vlan_tag
= hton16(vlan_tag
);
1107 } else if (ntoh16(eh
->ether_type
) == ETHER_TYPE_IP
) {
1108 uint8
*ip_body
= pktdata
+ sizeof(struct ether_header
);
1109 uint8 tos_tc
= IP_TOS46(ip_body
);
1110 priority
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
1114 ASSERT(priority
>= 0 && priority
<= MAXPRIO
);
1115 PKTSETPRIO(pkt
, priority
);
1116 return (rc
| priority
);
1119 static char bcm_undeferrstr
[BCME_STRLEN
];
1121 static const char *bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
1123 /* Convert the error codes into related error strings */
1125 bcmerrorstr(int bcmerror
)
1127 /* check if someone added a bcmerror code but forgot to add errorstring */
1128 ASSERT(ABS(BCME_LAST
) == (ARRAYSIZE(bcmerrorstrtable
) - 1));
1130 if (bcmerror
> 0 || bcmerror
< BCME_LAST
) {
1131 snprintf(bcm_undeferrstr
, BCME_STRLEN
, "Undefined error %d", bcmerror
);
1132 return bcm_undeferrstr
;
1135 ASSERT(strlen(bcmerrorstrtable
[-bcmerror
]) < BCME_STRLEN
);
1137 return bcmerrorstrtable
[-bcmerror
];
1142 BCMINITFN(bcm_nvram_refresh
)(char *flash
)
1147 ASSERT(flash
!= NULL
);
1149 /* default "empty" vars cache */
1152 if ((ret
= nvram_getall(flash
, NVRAM_SPACE
)))
1155 /* determine nvram length */
1156 for (i
= 0; i
< NVRAM_SPACE
; i
++) {
1157 if (flash
[i
] == '\0' && flash
[i
+1] == '\0')
1168 bcm_nvram_vars(uint
*length
)
1171 /* cache may be stale if nvram is read/write */
1173 ASSERT(!bcmreclaimed
);
1174 bcm_nvram_refresh(nvram_vars
);
1182 /* copy nvram vars into locally-allocated multi-string array */
1184 BCMINITFN(bcm_nvram_cache
)(void *sih
)
1190 if (vars_len
>= 0) {
1192 bcm_nvram_refresh(nvram_vars
);
1197 osh
= si_osh((si_t
*)sih
);
1199 /* allocate memory and read in flash */
1200 if (!(flash
= MALLOC(osh
, NVRAM_SPACE
))) {
1205 bcm_nvram_refresh(flash
);
1209 /* copy into a properly-sized buffer */
1210 if (!(nvram_vars
= MALLOC(osh
, vars_len
))) {
1213 bcopy(flash
, nvram_vars
, vars_len
);
1215 MFREE(osh
, flash
, NVRAM_SPACE
);
1217 /* cache must be full size of nvram if read/write */
1219 #endif /* BCMNVRAMR */
1224 #endif /* WLC_LOW */
1226 #ifdef BCMDBG_PKT /* pkt logging for debugging */
1227 /* Add a packet to the pktlist */
1229 pktlist_add(pktlist_info_t
*pktlist
, void *pkt
)
1232 ASSERT(pktlist
->count
< PKTLIST_SIZE
);
1234 /* Verify the packet is not already part of the list */
1235 for (i
= 0; i
< pktlist
->count
; i
++) {
1236 if (pktlist
->list
[i
] == pkt
)
1239 pktlist
->list
[pktlist
->count
] = pkt
;
1244 /* Remove a packet from the pktlist */
1246 pktlist_remove(pktlist_info_t
*pktlist
, void *pkt
)
1249 uint num
= pktlist
->count
;
1251 /* find the index where pkt exists */
1252 for (i
= 0; i
< num
; i
++)
1254 /* check for the existence of pkt in the list */
1255 if (pktlist
->list
[i
] == pkt
)
1257 /* replace with the last element */
1258 pktlist
->list
[i
] = pktlist
->list
[num
-1];
1264 printf("%s: pktlist %p count %d pkt %p\n", __FUNCTION__
,
1265 pktlist
, pktlist
->count
, pkt
);
1269 /* Dump the pktlist (and the contents of each packet if 'data'
1270 * is set). 'buf' should be large enough
1274 pktlist_dump(pktlist_info_t
*pktlist
, char *buf
)
1281 buf
+= sprintf(buf
, "Packet list dump:\n");
1283 for (i
= 0; i
< (pktlist
->count
); i
++) {
1284 buf
+= sprintf(buf
, "0x%p\t", pktlist
->list
[i
]);
1286 #ifdef NOTDEF /* Remove this ifdef to print pkttag and pktdata */
1287 if (PKTTAG(pktlist
->list
[i
])) {
1289 buf
+= sprintf(buf
, "Pkttag(in hex): ");
1290 buf
+= bcm_format_hex(buf
, PKTTAG(pktlist
->list
[i
]), OSL_PKTTAG_SZ
);
1292 buf
+= sprintf(buf
, "Pktdata(in hex): ");
1293 buf
+= bcm_format_hex(buf
, PKTDATA(NULL
, pktlist
->list
[i
]),
1294 PKTLEN(NULL
, pktlist
->list
[i
]));
1297 buf
+= sprintf(buf
, "\n");
1301 #endif /* BCMDBG_PKT */
1303 /* iovar table lookup */
1305 bcm_iovar_lookup(const bcm_iovar_t
*table
, const char *name
)
1307 const bcm_iovar_t
*vi
;
1308 const char *lookup_name
;
1310 /* skip any ':' delimited option prefixes */
1311 lookup_name
= strrchr(name
, ':');
1312 if (lookup_name
!= NULL
)
1317 ASSERT(table
!= NULL
);
1319 for (vi
= table
; vi
->name
; vi
++) {
1320 if (!strcmp(vi
->name
, lookup_name
))
1323 /* ran to end of table */
1325 return NULL
; /* var name not found */
1329 bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
1333 /* length check on io buf */
1342 /* all integers are int32 sized args at the ioctl interface */
1343 if (len
< (int)sizeof(int)) {
1344 bcmerror
= BCME_BUFTOOSHORT
;
1349 /* buffer must meet minimum length requirement */
1350 if (len
< vi
->minlen
) {
1351 bcmerror
= BCME_BUFTOOSHORT
;
1357 /* Cannot return nil... */
1358 bcmerror
= BCME_UNSUPPORTED
;
1360 /* Set is an action w/o parameters */
1361 bcmerror
= BCME_BUFTOOLONG
;
1366 /* unknown type for length check in iovar info */
1368 bcmerror
= BCME_UNSUPPORTED
;
1374 #endif /* BCMDRIVER */
1377 /*******************************************************************************
1380 * Computes a crc8 over the input data using the polynomial:
1382 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1384 * The caller provides the initial value (either CRC8_INIT_VALUE
1385 * or the previous returned value) to allow for processing of
1386 * discontiguous blocks of data. When generating the CRC the
1387 * caller is responsible for complementing the final return value
1388 * and inserting it into the byte stream. When checking, a final
1389 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1391 * Reference: Dallas Semiconductor Application Note 27
1392 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1393 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1394 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1396 * ****************************************************************************
1399 static const uint8 crc8_table
[256] = {
1400 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1401 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1402 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1403 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1404 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1405 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1406 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1407 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1408 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1409 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1410 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1411 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1412 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1413 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1414 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1415 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1416 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1417 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1418 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1419 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1420 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1421 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1422 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1423 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1424 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1425 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1426 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1427 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1428 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1429 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1430 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1431 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1434 #define CRC_INNER_LOOP(n, c, x) \
1435 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1439 uint8
*pdata
, /* pointer to array of data to process */
1440 uint nbytes
, /* number of input data bytes to process */
1441 uint8 crc
/* either CRC8_INIT_VALUE or previous return value */
1444 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1445 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1447 while (nbytes
-- > 0)
1448 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
1453 /*******************************************************************************
1456 * Computes a crc16 over the input data using the polynomial:
1458 * x^16 + x^12 +x^5 + 1
1460 * The caller provides the initial value (either CRC16_INIT_VALUE
1461 * or the previous returned value) to allow for processing of
1462 * discontiguous blocks of data. When generating the CRC the
1463 * caller is responsible for complementing the final return value
1464 * and inserting it into the byte stream. When checking, a final
1465 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1467 * Reference: Dallas Semiconductor Application Note 27
1468 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1469 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1470 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1472 * ****************************************************************************
1475 static const uint16 crc16_table
[256] = {
1476 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1477 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1478 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1479 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1480 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1481 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1482 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1483 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1484 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1485 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1486 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1487 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1488 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1489 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1490 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1491 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1492 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1493 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1494 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1495 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1496 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1497 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1498 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1499 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1500 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1501 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1502 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1503 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1504 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1505 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1506 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1507 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1512 uint8
*pdata
, /* pointer to array of data to process */
1513 uint nbytes
, /* number of input data bytes to process */
1514 uint16 crc
/* either CRC16_INIT_VALUE or previous return value */
1517 while (nbytes
-- > 0)
1518 CRC_INNER_LOOP(16, crc
, *pdata
++);
1522 static const uint32 crc32_table
[256] = {
1523 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1524 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1525 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1526 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1527 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1528 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1529 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1530 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1531 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1532 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1533 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1534 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1535 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1536 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1537 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1538 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1539 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1540 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1541 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1542 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1543 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1544 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1545 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1546 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1547 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1548 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1549 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1550 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1551 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1552 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1553 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1554 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1555 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1556 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1557 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1558 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1559 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1560 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1561 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1562 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1563 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1564 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1565 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1566 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1567 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1568 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1569 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1570 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1571 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1572 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1573 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1574 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1575 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1576 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1577 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1578 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1579 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1580 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1581 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1582 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1583 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1584 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1585 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1586 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1591 uint8
*pdata
, /* pointer to array of data to process */
1592 uint nbytes
, /* number of input data bytes to process */
1593 uint32 crc
/* either CRC32_INIT_VALUE or previous return value */
1599 ulong
*tptr
= (ulong
*)tmp
;
1601 /* in case the beginning of the buffer isn't aligned */
1602 pend
= (uint8
*)((uint
)(pdata
+ 3) & 0xfffffffc);
1603 nbytes
-= (pend
- pdata
);
1604 while (pdata
< pend
)
1605 CRC_INNER_LOOP(32, crc
, *pdata
++);
1607 /* handle bulk of data as 32-bit words */
1608 pend
= pdata
+ (nbytes
& 0xfffffffc);
1609 while (pdata
< pend
) {
1610 *tptr
= *(ulong
*)pdata
;
1611 pdata
+= sizeof(ulong
*);
1612 CRC_INNER_LOOP(32, crc
, tmp
[0]);
1613 CRC_INNER_LOOP(32, crc
, tmp
[1]);
1614 CRC_INNER_LOOP(32, crc
, tmp
[2]);
1615 CRC_INNER_LOOP(32, crc
, tmp
[3]);
1618 /* 1-3 bytes at end of buffer */
1619 pend
= pdata
+ (nbytes
& 0x03);
1620 while (pdata
< pend
)
1621 CRC_INNER_LOOP(32, crc
, *pdata
++);
1623 pend
= pdata
+ nbytes
;
1624 while (pdata
< pend
)
1625 CRC_INNER_LOOP(32, crc
, *pdata
++);
1626 #endif /* __mips__ */
1632 #define CLEN 1499 /* CRC Length */
1633 #define CBUFSIZ (CLEN+4)
1634 #define CNBUFS 5 /* # of bufs */
1643 uint32 crc32tv
[CNBUFS
] =
1644 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1646 ASSERT((buf
= MALLOC(CBUFSIZ
*CNBUFS
)) != NULL
);
1648 /* step through all possible alignments */
1649 for (l
= 0; l
<= 4; l
++) {
1650 for (j
= 0; j
< CNBUFS
; j
++) {
1652 for (k
= 0; k
< len
[j
]; k
++)
1653 *(buf
+ j
*CBUFSIZ
+ (k
+l
)) = (j
+k
) & 0xff;
1656 for (j
= 0; j
< CNBUFS
; j
++) {
1657 crcr
= crc32(buf
+ j
*CBUFSIZ
+ l
, len
[j
], CRC32_INIT_VALUE
);
1658 ASSERT(crcr
== crc32tv
[j
]);
1662 MFREE(buf
, CBUFSIZ
*CNBUFS
);
1668 * Advance from the current 1-byte tag/1-byte length/variable-length value
1669 * triple, to the next, returning a pointer to the next.
1670 * If the current or next TLV is invalid (does not fit in given buffer length),
1672 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1673 * by the TLV parameter's length if it is valid.
1676 BCMROMFN(bcm_next_tlv
)(bcm_tlv_t
*elt
, int *buflen
)
1680 /* validate current elt */
1681 if (!bcm_valid_tlv(elt
, *buflen
))
1684 /* advance to next elt */
1686 elt
= (bcm_tlv_t
*)(elt
->data
+ len
);
1687 *buflen
-= (2 + len
);
1689 /* validate next elt */
1690 if (!bcm_valid_tlv(elt
, *buflen
))
1697 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1698 * triples, returning a pointer to the substring whose first element
1702 BCMROMFN(bcm_parse_tlvs
)(void *buf
, int buflen
, uint key
)
1707 elt
= (bcm_tlv_t
*)buf
;
1710 /* find tagged parameter */
1711 while (totlen
>= 2) {
1714 /* validate remaining totlen */
1715 if ((elt
->id
== key
) && (totlen
>= (len
+ 2)))
1718 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ 2));
1719 totlen
-= (len
+ 2);
1726 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1727 * triples, returning a pointer to the substring whose first element
1728 * matches tag. Stop parsing when we see an element whose ID is greater
1729 * than the target key.
1732 BCMROMFN(bcm_parse_ordered_tlvs
)(void *buf
, int buflen
, uint key
)
1737 elt
= (bcm_tlv_t
*)buf
;
1740 /* find tagged parameter */
1741 while (totlen
>= 2) {
1745 /* Punt if we start seeing IDs > than target key */
1749 /* validate remaining totlen */
1750 if ((id
== key
) && (totlen
>= (len
+ 2)))
1753 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ 2));
1754 totlen
-= (len
+ 2);
1759 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1760 defined(BCMDBG_DUMP)
1762 bcm_format_flags(const bcm_bit_desc_t
*bd
, uint32 flags
, char* buf
, int len
)
1767 int slen
= 0, nlen
= 0;
1771 if (len
< 2 || !buf
)
1777 for (i
= 0; flags
!= 0; i
++) {
1780 if (bit
== 0 && flags
) {
1781 /* print any unnamed bits */
1782 snprintf(hexstr
, 16, "0x%X", flags
);
1784 flags
= 0; /* exit loop */
1785 } else if ((flags
& bit
) == 0)
1787 nlen
= strlen(name
);
1791 if (p
!= buf
) p
+= snprintf(p
, 2, " "); /* btwn flag space */
1792 strncpy(p
, name
, nlen
+ 1);
1796 slen
= 1; /* account for btwn flag space */
1799 /* indicate the str was too short */
1802 p
--; /* overwrite last char */
1803 p
+= snprintf(p
, 2, ">");
1806 return (int)(p
- buf
);
1809 /* print bytes formatted as hex to a string. return the resulting string length */
1811 bcm_format_hex(char *str
, const void *bytes
, int len
)
1815 const uint8
*src
= (const uint8
*)bytes
;
1817 for (i
= 0; i
< len
; i
++) {
1818 p
+= snprintf(p
, 3, "%02X", *src
);
1821 return (int)(p
- str
);
1824 /* pretty hex print a contiguous buffer */
1826 prhex(const char *msg
, uchar
*buf
, uint nbytes
)
1829 int len
= sizeof(line
);
1833 if (msg
&& (msg
[0] != '\0'))
1834 printf("%s:\n", msg
);
1837 for (i
= 0; i
< nbytes
; i
++) {
1839 nchar
= snprintf(p
, len
, " %04d: ", i
); /* line prefix */
1844 nchar
= snprintf(p
, len
, "%02x ", buf
[i
]);
1850 printf("%s\n", line
); /* flush line */
1856 /* flush last partial line */
1858 printf("%s\n", line
);
1864 bcm_chipname(uint chipid
, char *buf
, uint len
)
1868 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
1869 snprintf(buf
, len
, fmt
, chipid
);
1873 /* Produce a human-readable string for boardrev */
1875 bcm_brev_str(uint32 brev
, char *buf
)
1878 snprintf(buf
, 8, "%d.%d", (brev
& 0xf0) >> 4, brev
& 0xf);
1880 snprintf(buf
, 8, "%c%03x", ((brev
& 0xf000) == 0x1000) ? 'P' : 'A', brev
& 0xfff);
1885 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1887 /* dump large strings to console */
1896 max_len
= BUFSIZE_TODUMP_ATONCE
;
1898 while (len
> max_len
) {
1900 buf
[max_len
] = '\0';
1907 /* print the remaining string */
1908 printf("%s\n", buf
);
1912 /* routine to dump fields in a fileddesc structure */
1914 bcmdumpfields(bcmutl_rdreg_rtn read_rtn
, void *arg0
, uint arg1
, struct fielddesc
*fielddesc_array
,
1915 char *buf
, uint32 bufsize
)
1919 struct fielddesc
*cur_ptr
;
1922 cur_ptr
= fielddesc_array
;
1924 while (bufsize
> 1) {
1925 if (cur_ptr
->nameandfmt
== NULL
)
1927 len
= snprintf(buf
, bufsize
, cur_ptr
->nameandfmt
,
1928 read_rtn(arg0
, arg1
, cur_ptr
->offset
));
1929 /* check for snprintf overflow or error */
1930 if (len
< 0 || (uint32
)len
>= bufsize
)
1941 bcm_mkiovar(char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
1945 len
= strlen(name
) + 1;
1947 if ((len
+ datalen
) > buflen
)
1950 strncpy(buf
, name
, buflen
);
1952 /* append data onto the end of the name string */
1953 memcpy(&buf
[len
], data
, datalen
);
1960 /* Quarter dBm units to mW
1961 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1962 * Table is offset so the last entry is largest mW value that fits in
1966 #define QDBM_OFFSET 153 /* Offset for first entry */
1967 #define QDBM_TABLE_LEN 40 /* Table size */
1969 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1970 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1972 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1974 /* Largest mW value that will round down to the last table entry,
1975 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1976 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1978 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1980 static const uint16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
1981 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1982 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1983 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1984 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1985 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1986 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1990 BCMROMFN(bcm_qdbm_to_mw
)(uint8 qdbm
)
1993 int idx
= qdbm
- QDBM_OFFSET
;
1995 if (idx
>= QDBM_TABLE_LEN
) {
1996 /* clamp to max uint16 mW value */
2000 /* scale the qdBm index up to the range of the table 0-40
2001 * where an offset of 40 qdBm equals a factor of 10 mW.
2008 /* return the mW value scaled down to the correct factor of 10,
2009 * adding in factor/2 to get proper rounding.
2011 return ((nqdBm_to_mW_map
[idx
] + factor
/2) / factor
);
2015 BCMROMFN(bcm_mw_to_qdbm
)(uint16 mw
)
2022 /* handle boundary case */
2026 offset
= QDBM_OFFSET
;
2028 /* move mw into the range of the table */
2029 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
2034 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
-1; qdbm
++) {
2035 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+1] -
2036 nqdBm_to_mW_map
[qdbm
])/2;
2037 if (mw_uint
< boundary
) break;
2040 qdbm
+= (uint8
)offset
;
2047 BCMROMFN(bcm_bitcount
)(uint8
*bitmap
, uint length
)
2049 uint bitcount
= 0, i
;
2051 for (i
= 0; i
< length
; i
++) {
2064 /* Initialization of bcmstrbuf structure */
2066 bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
2068 b
->origsize
= b
->size
= size
;
2069 b
->origbuf
= b
->buf
= buf
;
2072 /* Buffer sprintf wrapper to guard against buffer overflow */
2074 bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
2080 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
2082 /* Non Ansi C99 compliant returns -1,
2083 * Ansi compliant return r >= b->size,
2084 * bcmstdlib returns 0, handle all
2086 if ((r
== -1) || (r
>= (int)b
->size
) || (r
== 0)) {
2099 bcm_inc_bytes(uchar
*num
, int num_bytes
, uint8 amount
)
2103 for (i
= 0; i
< num_bytes
; i
++) {
2105 if (num
[i
] >= amount
)
2112 bcm_cmp_bytes(uchar
*arg1
, uchar
*arg2
, uint8 nbytes
)
2116 for (i
= nbytes
- 1; i
>= 0; i
--) {
2117 if (arg1
[i
] != arg2
[i
])
2118 return (arg1
[i
] - arg2
[i
]);
2124 bcm_print_bytes(char *name
, const uchar
*data
, int len
)
2129 printf("%s: %d \n", name
? name
: "", len
);
2130 for (i
= 0; i
< len
; i
++) {
2131 printf("%02x ", *data
++);
2133 if (per_line
== 16) {
2141 #endif /* BCMDRIVER */