2 * Driver O/S-independent utility routines
4 * Copyright 2007, 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.
25 #endif /* BCMDRIVER */
26 #if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || \
27 defined(_CFE_) || defined(EFI)
29 #include <bcmstdlib.h>
31 #include <bcmendian.h>
33 #include <proto/ethernet.h>
34 #include <proto/vlan.h>
35 #include <proto/bcmip.h>
36 #include <proto/bcmtcp.h>
37 #include <proto/802.1d.h>
44 /* nvram vars cache */
45 static char *nvram_vars
= NULL
;
46 static int vars_len
= -1;
48 /* copy a pkt buffer chain into a buffer */
50 pktcopy(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
55 len
= 4096; /* "infinite" */
57 /* skip 'offset' bytes */
58 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
59 if (offset
< (uint
)PKTLEN(osh
, p
))
61 offset
-= PKTLEN(osh
, p
);
68 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
69 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
70 bcopy(PKTDATA(osh
, p
) + offset
, buf
, n
);
80 /* return total length of buffer chain */
82 pkttotlen(osl_t
*osh
, void *p
)
87 for (; p
; p
= PKTNEXT(osh
, p
))
88 total
+= PKTLEN(osh
, p
);
92 /* return the last buffer of chained pkt */
94 pktlast(osl_t
*osh
, void *p
)
96 for (; PKTNEXT(osh
, p
); p
= PKTNEXT(osh
, p
))
104 * osl multiple-precedence packet queue
105 * hi_prec is always >= the number of the highest non-empty precedence
108 pktq_penq(struct pktq
*pq
, int prec
, void *p
)
112 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
113 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
115 ASSERT(!pktq_full(pq
));
116 ASSERT(!pktq_pfull(pq
, prec
));
121 PKTSETLINK(q
->tail
, p
);
130 if (pq
->hi_prec
< prec
)
131 pq
->hi_prec
= (uint8
)prec
;
137 pktq_penq_head(struct pktq
*pq
, int prec
, void *p
)
141 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
142 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
144 ASSERT(!pktq_full(pq
));
145 ASSERT(!pktq_pfull(pq
, prec
));
152 PKTSETLINK(p
, q
->head
);
158 if (pq
->hi_prec
< prec
)
159 pq
->hi_prec
= (uint8
)prec
;
165 pktq_pdeq(struct pktq
*pq
, int prec
)
170 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
174 if ((p
= q
->head
) == NULL
)
177 if ((q
->head
= PKTLINK(p
)) == NULL
)
190 pktq_pdeq_tail(struct pktq
*pq
, int prec
)
195 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
199 if ((p
= q
->head
) == NULL
)
202 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
206 PKTSETLINK(prev
, NULL
);
219 pktq_pflush(osl_t
*osh
, struct pktq
*pq
, int prec
, bool dir
)
227 q
->head
= PKTLINK(p
);
229 PKTFREE(osh
, p
, dir
);
239 pktq_pdel(struct pktq
*pq
, void *pktbuf
, int prec
)
244 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
251 if (q
->head
== pktbuf
) {
252 if ((q
->head
= PKTLINK(pktbuf
)) == NULL
)
255 for (p
= q
->head
; p
&& PKTLINK(p
) != pktbuf
; p
= PKTLINK(p
))
260 PKTSETLINK(p
, PKTLINK(pktbuf
));
261 if (q
->tail
== pktbuf
)
267 PKTSETLINK(pktbuf
, NULL
);
272 pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
276 ASSERT(num_prec
> 0 && num_prec
<= PKTQ_MAX_PREC
);
278 /* pq is variable size; only zero out what's requested */
279 bzero(pq
, OFFSETOF(struct pktq
, q
) + (sizeof(struct pktq_prec
) * num_prec
));
281 pq
->num_prec
= (uint16
)num_prec
;
283 pq
->max
= (uint16
)max_len
;
285 for (prec
= 0; prec
< num_prec
; prec
++)
286 pq
->q
[prec
].max
= pq
->max
;
290 pktq_setmax(struct pktq
*pq
, int max_len
)
297 pq
->max
= (uint16
)max_len
;
298 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
299 pq
->q
[prec
].max
= pq
->max
;
305 pktq_deq(struct pktq
*pq
, int *prec_out
)
314 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
319 if ((p
= q
->head
) == NULL
)
322 if ((q
->head
= PKTLINK(p
)) == NULL
)
338 pktq_deq_tail(struct pktq
*pq
, int *prec_out
)
347 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
348 if (pq
->q
[prec
].head
)
353 if ((p
= q
->head
) == NULL
)
356 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
360 PKTSETLINK(prev
, NULL
);
378 pktq_peek(struct pktq
*pq
, int *prec_out
)
385 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
391 return (pq
->q
[prec
].head
);
395 pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
402 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
403 if (pq
->q
[prec
].head
)
409 return (pq
->q
[prec
].tail
);
413 pktq_flush(osl_t
*osh
, struct pktq
*pq
, bool dir
)
416 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
417 pktq_pflush(osh
, pq
, prec
, dir
);
418 ASSERT(pq
->len
== 0);
421 /* Return sum of lengths of a specific set of precedences */
423 pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
429 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
430 if (prec_bmp
& (1 << prec
))
431 len
+= pq
->q
[prec
].len
;
436 /* Priority dequeue from a specific set of precedences */
438 pktq_mdeq(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
447 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
450 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
456 if ((p
= q
->head
) == NULL
)
459 if ((q
->head
= PKTLINK(p
)) == NULL
)
473 #endif /* BCMDRIVER */
475 #ifndef BCMROMOFFLOAD
477 const unsigned char bcm_ctype
[] = {
478 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 0-7 */
479 _BCM_C
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
,
481 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 16-23 */
482 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 24-31 */
483 _BCM_S
|_BCM_SP
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 32-39 */
484 _BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 40-47 */
485 _BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
, /* 48-55 */
486 _BCM_D
,_BCM_D
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 56-63 */
487 _BCM_P
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
,
488 _BCM_U
|_BCM_X
, _BCM_U
, /* 64-71 */
489 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 72-79 */
490 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 80-87 */
491 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 88-95 */
492 _BCM_P
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
,
493 _BCM_L
|_BCM_X
, _BCM_L
, /* 96-103 */
494 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 104-111 */
495 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 112-119 */
496 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_C
, /* 120-127 */
497 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
499 _BCM_S
|_BCM_SP
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
500 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 160-175 */
501 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
502 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 176-191 */
503 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
,
504 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, /* 192-207 */
505 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_P
, _BCM_U
, _BCM_U
, _BCM_U
,
506 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_L
, /* 208-223 */
507 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
,
508 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, /* 224-239 */
509 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_P
, _BCM_L
, _BCM_L
, _BCM_L
,
510 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
/* 240-255 */
514 BCMROMFN(bcm_strtoul
)(char *cp
, char **endp
, uint base
)
521 while (bcm_isspace(*cp
))
526 else if (cp
[0] == '-') {
533 if ((cp
[1] == 'x') || (cp
[1] == 'X')) {
542 } else if (base
== 16 && (cp
[0] == '0') && ((cp
[1] == 'x') || (cp
[1] == 'X'))) {
548 while (bcm_isxdigit(*cp
) &&
549 (value
= bcm_isdigit(*cp
) ? *cp
-'0' : bcm_toupper(*cp
)-'A'+10) < base
) {
550 result
= result
*base
+ value
;
555 result
= (ulong
)(result
* -1);
564 BCMROMFN(bcm_atoi
)(char *s
)
566 return (int)bcm_strtoul(s
, NULL
, 10);
569 /* return pointer to location of substring 'needle' in 'haystack' */
571 BCMROMFN(bcmstrstr
)(char *haystack
, char *needle
)
576 if ((haystack
== NULL
) || (needle
== NULL
))
579 nlen
= strlen(needle
);
580 len
= strlen(haystack
) - nlen
+ 1;
582 for (i
= 0; i
< len
; i
++)
583 if (memcmp(needle
, &haystack
[i
], nlen
) == 0)
584 return (&haystack
[i
]);
589 BCMROMFN(bcmstrcat
)(char *dest
, const char *src
)
591 strcpy(&dest
[strlen(dest
)], src
);
596 BCMROMFN(bcmstrncat
)(char *dest
, const char *src
, uint size
)
601 p
= dest
+ strlen(dest
);
604 while (p
!= endp
&& (*p
++ = *src
++) != '\0')
610 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
612 BCMROMFN(bcm_ether_atoe
)(char *p
, struct ether_addr
*ea
)
617 ea
->octet
[i
++] = (char) bcm_strtoul(p
, &p
, 16);
624 #endif /* !BCMROMOFFLOAD */
626 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
627 /* registry routine buffer preparation utility functions:
628 * parameter order is like strncpy, but returns count
629 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
645 /* wbuflen is in bytes */
646 wbuflen
/= sizeof(ushort
);
648 for (i
= 0; i
< wbuflen
; ++i
) {
651 *abuf
++ = (char) *wbuf
++;
658 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
661 bcm_ether_ntoa(struct ether_addr
*ea
, char *buf
)
663 snprintf(buf
, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
664 ea
->octet
[0]&0xff, ea
->octet
[1]&0xff, ea
->octet
[2]&0xff,
665 ea
->octet
[3]&0xff, ea
->octet
[4]&0xff, ea
->octet
[5]&0xff);
670 bcm_ip_ntoa(struct ipv4_addr
*ia
, char *buf
)
672 snprintf(buf
, 16, "%d.%d.%d.%d",
673 ia
->addr
[0], ia
->addr
[1], ia
->addr
[2], ia
->addr
[3]);
684 for (i
= 0; i
< ms
; i
++) {
690 * Search the name=value vars for a specific one and return its value.
691 * Returns NULL if not found.
694 getvar(char *vars
, const char *name
)
709 /* first look in vars[] */
710 for (s
= vars
; s
&& *s
;) {
712 if ((bcmp(s
, name
, len
) == 0) && (s
[len
] == '='))
719 /* then query nvram */
720 return (nvram_get(name
));
721 #endif /* _MINOSL_ */
725 * Search the vars for a specific one and return its value as
726 * an integer. Returns 0 if not found.
729 getintvar(char *vars
, const char *name
)
736 if ((val
= getvar(vars
, name
)) == NULL
)
739 return (bcm_strtoul(val
, NULL
, 0));
740 #endif /* _MINOSL_ */
744 /* Search for token in comma separated token-string */
746 findmatch(char *string
, char *name
)
753 while ((c
= strchr(string
, ',')) != NULL
) {
754 if (len
== (uint
)(c
- string
) && !strncmp(string
, name
, len
))
759 return (!strcmp(string
, name
));
762 /* Return gpio pin number assigned to the named pin
764 * Variable should be in format:
766 * gpio<N>=pin_name,pin_name
768 * This format allows multiple features to share the gpio with mutual
771 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
772 * and if def_pin is not used by others.
775 getgpiopin(char *vars
, char *pin_name
, uint def_pin
)
777 char name
[] = "gpioXXXX";
781 /* Go thru all possibilities till a match in pin name */
782 for (pin
= 0; pin
< GPIO_NUMPINS
; pin
++) {
783 snprintf(name
, sizeof(name
), "gpio%d", pin
);
784 val
= getvar(vars
, name
);
785 if (val
&& findmatch(val
, pin_name
))
789 if (def_pin
!= GPIO_PIN_NOTDEFINED
) {
790 /* make sure the default pin is not used by someone else */
791 snprintf(name
, sizeof(name
), "gpio%d", def_pin
);
792 if (getvar(vars
, name
)) {
793 def_pin
= GPIO_PIN_NOTDEFINED
;
802 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
810 /* last entry logged */
811 static uint logi
= 0;
812 /* next entry to read */
813 static uint readi
= 0;
818 BCMPERF_ENABLE_INSTRCOUNT();
819 BCMPERF_ENABLE_ICACHE_MISS();
820 BCMPERF_ENABLE_ICACHE_HIT();
824 bcmlog(char *fmt
, uint a1
, uint a2
)
826 static uint last
= 0;
828 OSL_GETCYCLES(cycles
);
832 logtab
[i
].cycles
= cycles
- last
;
837 logi
= (i
+ 1) % LOGSIZE
;
845 static uint last
= 0;
846 static uint32 ic_miss
= 0;
847 static uint32 instr_count
= 0;
849 uint32 instr_count_cur
;
852 OSL_GETCYCLES(cycles
);
853 BCMPERF_GETICACHE_MISS(ic_miss_cur
);
854 BCMPERF_GETINSTRCOUNT(instr_count_cur
);
858 logtab
[i
].cycles
= cycles
- last
;
859 logtab
[i
].a1
= ic_miss_cur
- ic_miss
;
860 logtab
[i
].a2
= instr_count_cur
- instr_count
;
863 logi
= (i
+ 1) % LOGSIZE
;
866 instr_count
= instr_count_cur
;
867 ic_miss
= ic_miss_cur
;
872 bcmdumplog(char *buf
, int size
)
878 limit
= buf
+ size
- 80;
886 /* print in chronological order */
888 for (j
= 0; j
< num
&& (buf
< limit
); readi
= (readi
+ 1) % LOGSIZE
, j
++) {
889 if (logtab
[readi
].fmt
== NULL
)
892 buf
+= sprintf(buf
, "%d\t", logtab
[readi
].cycles
);
893 buf
+= sprintf(buf
, logtab
[readi
].fmt
, logtab
[readi
].a1
, logtab
[readi
].a2
);
894 buf
+= sprintf(buf
, "\n");
901 * Dump one log entry at a time.
902 * Return index of next entry or -1 when no more .
905 bcmdumplogent(char *buf
, uint i
)
910 * If buf is NULL, return the starting index,
911 * interpreting i as the indicator of last 'i' entries to dump.
914 i
= ((i
> 0) && (i
< (LOGSIZE
- 1))) ? i
: (LOGSIZE
- 1);
915 return ((logi
- i
) % LOGSIZE
);
926 for (; (i
!= logi
) && !hit
; i
= (i
+ 1) % LOGSIZE
) {
927 if (logtab
[i
].fmt
== NULL
)
929 buf
+= sprintf(buf
, "%d: %d\t", i
, logtab
[i
].cycles
);
930 buf
+= sprintf(buf
, logtab
[i
].fmt
, logtab
[i
].a1
, logtab
[i
].a2
);
931 buf
+= sprintf(buf
, "\n");
938 #endif /* BCMPERFSTATS */
941 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
942 * Also updates the inplace vlan tag if requested.
943 * For debugging, it returns an indication of what it did.
946 pktsetprio(void *pkt
, bool update_vtag
)
948 struct ether_header
*eh
;
949 struct ethervlan_header
*evh
;
954 pktdata
= (uint8
*) PKTDATA(NULL
, pkt
);
955 ASSERT(ISALIGNED((uintptr
)pktdata
, sizeof(uint16
)));
957 eh
= (struct ether_header
*) pktdata
;
959 if (ntoh16(eh
->ether_type
) == ETHER_TYPE_8021Q
) {
961 int vlan_prio
, dscp_prio
= 0;
963 evh
= (struct ethervlan_header
*)eh
;
965 vlan_tag
= ntoh16(evh
->vlan_tag
);
966 vlan_prio
= (int) (vlan_tag
>> VLAN_PRI_SHIFT
) & VLAN_PRI_MASK
;
968 if (ntoh16(evh
->ether_type
) == ETHER_TYPE_IP
) {
969 uint8
*ip_body
= pktdata
+ sizeof(struct ethervlan_header
);
970 uint8 tos_tc
= IP_TOS(ip_body
);
971 dscp_prio
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
972 if ((IP_VER(ip_body
) == IP_VER_4
) && (IPV4_PROT(ip_body
) == IP_PROT_TCP
)) {
978 ip_len
= IPV4_PAYLOAD_LEN(ip_body
);
979 tcp_hdr
= IPV4_NO_OPTIONS_PAYLOAD(ip_body
);
980 src_port
= TCP_SRC_PORT(tcp_hdr
);
981 src_port_exc
= (src_port
== 10110) || (src_port
== 10120) ||
982 (src_port
== 10130) || (src_port
== 10140);
984 if ((ip_len
== 40) && src_port_exc
&& TCP_IS_ACK(tcp_hdr
)) {
990 /* DSCP priority gets precedence over 802.1P (vlan tag) */
991 if (dscp_prio
!= 0) {
992 priority
= dscp_prio
;
995 priority
= vlan_prio
;
999 * If the DSCP priority is not the same as the VLAN priority,
1000 * then overwrite the priority field in the vlan tag, with the
1001 * DSCP priority value. This is required for Linux APs because
1002 * the VLAN driver on Linux, overwrites the skb->priority field
1003 * with the priority value in the vlan tag
1005 if (update_vtag
&& (priority
!= vlan_prio
)) {
1006 vlan_tag
&= ~(VLAN_PRI_MASK
<< VLAN_PRI_SHIFT
);
1007 vlan_tag
|= (uint16
)priority
<< VLAN_PRI_SHIFT
;
1008 evh
->vlan_tag
= hton16(vlan_tag
);
1011 } else if (ntoh16(eh
->ether_type
) == ETHER_TYPE_IP
) {
1012 uint8
*ip_body
= pktdata
+ sizeof(struct ether_header
);
1013 uint8 tos_tc
= IP_TOS(ip_body
);
1014 priority
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
1016 if ((IP_VER(ip_body
) == IP_VER_4
) && (IPV4_PROT(ip_body
) == IP_PROT_TCP
)) {
1022 ip_len
= IPV4_PAYLOAD_LEN(ip_body
);
1023 tcp_hdr
= IPV4_NO_OPTIONS_PAYLOAD(ip_body
);
1024 src_port
= TCP_SRC_PORT(tcp_hdr
);
1025 src_port_exc
= (src_port
== 10110) || (src_port
== 10120) ||
1026 (src_port
== 10130) || (src_port
== 10140);
1028 if ((ip_len
== 40) && src_port_exc
&& TCP_IS_ACK(tcp_hdr
)) {
1034 ASSERT(priority
>= 0 && priority
<= MAXPRIO
);
1035 PKTSETPRIO(pkt
, priority
);
1036 return (rc
| priority
);
1039 static char bcm_undeferrstr
[BCME_STRLEN
];
1041 static const char *bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
1043 /* Convert the error codes into related error strings */
1045 bcmerrorstr(int bcmerror
)
1047 /* check if someone added a bcmerror code but forgot to add errorstring */
1048 ASSERT(ABS(BCME_LAST
) == (ARRAYSIZE(bcmerrorstrtable
) - 1));
1050 if (bcmerror
> 0 || bcmerror
< BCME_LAST
) {
1051 snprintf(bcm_undeferrstr
, BCME_STRLEN
, "Undefined error %d", bcmerror
);
1052 return bcm_undeferrstr
;
1055 ASSERT(strlen(bcmerrorstrtable
[-bcmerror
]) < BCME_STRLEN
);
1057 return bcmerrorstrtable
[-bcmerror
];
1061 BCMINITFN(bcm_nvram_refresh
)(char *flash
)
1068 /* default "empty" vars cache */
1071 if ((ret
= nvram_getall(flash
, NVRAM_SPACE
)))
1074 /* determine nvram length */
1075 for (i
= 0; i
< NVRAM_SPACE
; i
++) {
1076 if (flash
[i
] == '\0' && flash
[i
+1] == '\0')
1087 bcm_nvram_vars(uint
*length
)
1090 /* cache may be stale if nvram is read/write */
1092 ASSERT(!bcmreclaimed
);
1093 bcm_nvram_refresh(nvram_vars
);
1101 /* copy nvram vars into locally-allocated multi-string array */
1103 BCMINITFN(bcm_nvram_cache
)(void *sbh
)
1109 if (vars_len
>= 0) {
1111 bcm_nvram_refresh(nvram_vars
);
1116 osh
= sb_osh((sb_t
*)sbh
);
1118 /* allocate memory and read in flash */
1119 if (!(flash
= MALLOC(osh
, NVRAM_SPACE
))) {
1124 bcm_nvram_refresh(flash
);
1128 /* copy into a properly-sized buffer */
1129 if (!(nvram_vars
= MALLOC(osh
, vars_len
))) {
1132 bcopy(flash
, nvram_vars
, vars_len
);
1134 MFREE(osh
, flash
, NVRAM_SPACE
);
1136 /* cache must be full size of nvram if read/write */
1138 #endif /* BCMNVRAMR */
1144 #ifdef BCMDBG_PKT /* pkt logging for debugging */
1145 /* Add a packet to the pktlist */
1147 pktlist_add(pktlist_info_t
*pktlist
, void *pkt
)
1150 ASSERT(pktlist
->count
< PKTLIST_SIZE
);
1152 /* Verify the packet is not already part of the list */
1153 for (i
= 0; i
< pktlist
->count
; i
++) {
1154 if (pktlist
->list
[i
] == pkt
)
1157 pktlist
->list
[pktlist
->count
] = pkt
;
1162 /* Remove a packet from the pktlist */
1164 pktlist_remove(pktlist_info_t
*pktlist
, void *pkt
)
1167 uint num
= pktlist
->count
;
1169 /* find the index where pkt exists */
1170 for (i
= 0; i
< num
; i
++)
1172 /* check for the existence of pkt in the list */
1173 if (pktlist
->list
[i
] == pkt
)
1175 /* replace with the last element */
1176 pktlist
->list
[i
] = pktlist
->list
[num
-1];
1184 /* Dump the pktlist (and the contents of each packet if 'data'
1185 * is set). 'buf' should be large enough
1189 pktlist_dump(pktlist_info_t
*pktlist
, char *buf
)
1196 buf
+= sprintf(buf
, "Packet list dump:\n");
1198 for (i
= 0; i
< (pktlist
->count
); i
++) {
1199 buf
+= sprintf(buf
, "0x%p\t", pktlist
->list
[i
]);
1201 #ifdef NOTDEF /* Remove this ifdef to print pkttag and pktdata */
1202 if (PKTTAG(pktlist
->list
[i
])) {
1204 buf
+= sprintf(buf
, "Pkttag(in hex): ");
1205 buf
+= bcm_format_hex(buf
, PKTTAG(pktlist
->list
[i
]), OSL_PKTTAG_SZ
);
1207 buf
+= sprintf(buf
, "Pktdata(in hex): ");
1208 buf
+= bcm_format_hex(buf
, PKTDATA(NULL
, pktlist
->list
[i
]),
1209 PKTLEN(NULL
, pktlist
->list
[i
]));
1212 buf
+= sprintf(buf
, "\n");
1216 #endif /* BCMDBG_PKT */
1218 /* iovar table lookup */
1220 bcm_iovar_lookup(const bcm_iovar_t
*table
, const char *name
)
1222 const bcm_iovar_t
*vi
;
1223 const char *lookup_name
;
1225 /* skip any ':' delimited option prefixes */
1226 lookup_name
= strrchr(name
, ':');
1227 if (lookup_name
!= NULL
)
1234 for (vi
= table
; vi
->name
; vi
++) {
1235 if (!strcmp(vi
->name
, lookup_name
))
1238 /* ran to end of table */
1240 return NULL
; /* var name not found */
1244 bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
1248 /* length check on io buf */
1257 /* all integers are int32 sized args at the ioctl interface */
1258 if (len
< (int)sizeof(int)) {
1259 bcmerror
= BCME_BUFTOOSHORT
;
1264 /* buffer must meet minimum length requirement */
1265 if (len
< vi
->minlen
) {
1266 bcmerror
= BCME_BUFTOOSHORT
;
1272 /* Cannot return nil... */
1273 bcmerror
= BCME_UNSUPPORTED
;
1275 /* Set is an action w/o parameters */
1276 bcmerror
= BCME_BUFTOOLONG
;
1281 /* unknown type for length check in iovar info */
1283 bcmerror
= BCME_UNSUPPORTED
;
1289 #endif /* BCMDRIVER */
1292 #ifndef BCMROMOFFLOAD
1293 /*******************************************************************************
1296 * Computes a crc8 over the input data using the polynomial:
1298 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1300 * The caller provides the initial value (either CRC8_INIT_VALUE
1301 * or the previous returned value) to allow for processing of
1302 * discontiguous blocks of data. When generating the CRC the
1303 * caller is responsible for complementing the final return value
1304 * and inserting it into the byte stream. When checking, a final
1305 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1307 * Reference: Dallas Semiconductor Application Note 27
1308 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1309 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1310 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1312 * ****************************************************************************
1315 static const uint8 crc8_table
[256] = {
1316 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1317 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1318 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1319 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1320 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1321 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1322 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1323 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1324 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1325 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1326 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1327 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1328 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1329 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1330 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1331 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1332 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1333 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1334 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1335 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1336 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1337 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1338 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1339 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1340 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1341 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1342 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1343 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1344 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1345 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1346 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1347 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1350 #define CRC_INNER_LOOP(n, c, x) \
1351 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1355 uint8
*pdata
, /* pointer to array of data to process */
1356 uint nbytes
, /* number of input data bytes to process */
1357 uint8 crc
/* either CRC8_INIT_VALUE or previous return value */
1360 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1361 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1363 while (nbytes
-- > 0)
1364 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
1369 /*******************************************************************************
1372 * Computes a crc16 over the input data using the polynomial:
1374 * x^16 + x^12 +x^5 + 1
1376 * The caller provides the initial value (either CRC16_INIT_VALUE
1377 * or the previous returned value) to allow for processing of
1378 * discontiguous blocks of data. When generating the CRC the
1379 * caller is responsible for complementing the final return value
1380 * and inserting it into the byte stream. When checking, a final
1381 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1383 * Reference: Dallas Semiconductor Application Note 27
1384 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1385 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1386 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1388 * ****************************************************************************
1391 static const uint16 crc16_table
[256] = {
1392 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1393 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1394 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1395 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1396 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1397 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1398 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1399 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1400 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1401 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1402 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1403 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1404 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1405 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1406 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1407 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1408 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1409 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1410 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1411 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1412 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1413 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1414 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1415 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1416 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1417 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1418 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1419 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1420 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1421 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1422 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1423 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1428 uint8
*pdata
, /* pointer to array of data to process */
1429 uint nbytes
, /* number of input data bytes to process */
1430 uint16 crc
/* either CRC16_INIT_VALUE or previous return value */
1433 while (nbytes
-- > 0)
1434 CRC_INNER_LOOP(16, crc
, *pdata
++);
1438 static const uint32 crc32_table
[256] = {
1439 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1440 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1441 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1442 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1443 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1444 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1445 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1446 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1447 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1448 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1449 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1450 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1451 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1452 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1453 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1454 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1455 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1456 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1457 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1458 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1459 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1460 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1461 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1462 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1463 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1464 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1465 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1466 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1467 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1468 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1469 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1470 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1471 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1472 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1473 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1474 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1475 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1476 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1477 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1478 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1479 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1480 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1481 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1482 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1483 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1484 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1485 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1486 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1487 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1488 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1489 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1490 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1491 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1492 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1493 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1494 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1495 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1496 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1497 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1498 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1499 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1500 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1501 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1502 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1507 uint8
*pdata
, /* pointer to array of data to process */
1508 uint nbytes
, /* number of input data bytes to process */
1509 uint32 crc
/* either CRC32_INIT_VALUE or previous return value */
1515 ulong
*tptr
= (ulong
*)tmp
;
1517 /* in case the beginning of the buffer isn't aligned */
1518 pend
= (uint8
*)((uint
)(pdata
+ 3) & 0xfffffffc);
1519 nbytes
-= (pend
- pdata
);
1520 while (pdata
< pend
)
1521 CRC_INNER_LOOP(32, crc
, *pdata
++);
1523 /* handle bulk of data as 32-bit words */
1524 pend
= pdata
+ (nbytes
& 0xfffffffc);
1525 while (pdata
< pend
) {
1526 *tptr
= *(ulong
*)pdata
;
1527 pdata
+= sizeof(ulong
*);
1528 CRC_INNER_LOOP(32, crc
, tmp
[0]);
1529 CRC_INNER_LOOP(32, crc
, tmp
[1]);
1530 CRC_INNER_LOOP(32, crc
, tmp
[2]);
1531 CRC_INNER_LOOP(32, crc
, tmp
[3]);
1534 /* 1-3 bytes at end of buffer */
1535 pend
= pdata
+ (nbytes
& 0x03);
1536 while (pdata
< pend
)
1537 CRC_INNER_LOOP(32, crc
, *pdata
++);
1539 pend
= pdata
+ nbytes
;
1540 while (pdata
< pend
)
1541 CRC_INNER_LOOP(32, crc
, *pdata
++);
1542 #endif /* __mips__ */
1548 #define CLEN 1499 /* CRC Length */
1549 #define CBUFSIZ (CLEN+4)
1550 #define CNBUFS 5 /* # of bufs */
1552 void testcrc32(void)
1558 uint32 crc32tv
[CNBUFS
] =
1559 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1561 ASSERT((buf
= MALLOC(CBUFSIZ
*CNBUFS
)) != NULL
);
1563 /* step through all possible alignments */
1564 for (l
= 0; l
<= 4; l
++) {
1565 for (j
= 0; j
< CNBUFS
; j
++) {
1567 for (k
= 0; k
< len
[j
]; k
++)
1568 *(buf
+ j
*CBUFSIZ
+ (k
+l
)) = (j
+k
) & 0xff;
1571 for (j
= 0; j
< CNBUFS
; j
++) {
1572 crcr
= crc32(buf
+ j
*CBUFSIZ
+ l
, len
[j
], CRC32_INIT_VALUE
);
1573 ASSERT(crcr
== crc32tv
[j
]);
1577 MFREE(buf
, CBUFSIZ
*CNBUFS
);
1583 * Advance from the current 1-byte tag/1-byte length/variable-length value
1584 * triple, to the next, returning a pointer to the next.
1585 * If the current or next TLV is invalid (does not fit in given buffer length),
1587 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1588 * by the TLV parameter's length if it is valid.
1591 BCMROMFN(bcm_next_tlv
)(bcm_tlv_t
*elt
, int *buflen
)
1595 /* validate current elt */
1596 if (!bcm_valid_tlv(elt
, *buflen
))
1599 /* advance to next elt */
1601 elt
= (bcm_tlv_t
*)(elt
->data
+ len
);
1602 *buflen
-= (2 + len
);
1604 /* validate next elt */
1605 if (!bcm_valid_tlv(elt
, *buflen
))
1612 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1613 * triples, returning a pointer to the substring whose first element
1617 BCMROMFN(bcm_parse_tlvs
)(void *buf
, int buflen
, uint key
)
1622 elt
= (bcm_tlv_t
*)buf
;
1625 /* find tagged parameter */
1626 while (totlen
>= 2) {
1629 /* validate remaining totlen */
1630 if ((elt
->id
== key
) && (totlen
>= (len
+ 2)))
1633 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ 2));
1634 totlen
-= (len
+ 2);
1641 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1642 * triples, returning a pointer to the substring whose first element
1643 * matches tag. Stop parsing when we see an element whose ID is greater
1644 * than the target key.
1647 BCMROMFN(bcm_parse_ordered_tlvs
)(void *buf
, int buflen
, uint key
)
1652 elt
= (bcm_tlv_t
*)buf
;
1655 /* find tagged parameter */
1656 while (totlen
>= 2) {
1660 /* Punt if we start seeing IDs > than target key */
1664 /* validate remaining totlen */
1665 if ((id
== key
) && (totlen
>= (len
+ 2)))
1668 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ 2));
1669 totlen
-= (len
+ 2);
1673 #endif /* !BCMROMOFFLOAD */
1676 /* Produce a human-readable string for boardrev */
1678 bcm_brev_str(uint16 brev
, char *buf
)
1681 snprintf(buf
, 8, "%d.%d", (brev
& 0xf0) >> 4, brev
& 0xf);
1683 snprintf(buf
, 8, "%c%03x", ((brev
& 0xf000) == 0x1000) ? 'P' : 'A', brev
& 0xfff);
1688 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1690 /* dump large strings to console */
1692 printfbig(char *buf
)
1699 max_len
= BUFSIZE_TODUMP_ATONCE
;
1701 while (len
> max_len
) {
1703 buf
[max_len
] = '\0';
1710 /* print the remaining string */
1711 printf("%s\n", buf
);
1715 /* routine to dump fields in a fileddesc structure */
1717 bcmdumpfields(readreg_rtn read_rtn
, void *arg0
, void *arg1
, struct fielddesc
*fielddesc_array
,
1718 char *buf
, uint32 bufsize
)
1722 struct fielddesc
*cur_ptr
;
1725 cur_ptr
= fielddesc_array
;
1727 while (bufsize
> 1) {
1728 if (cur_ptr
->nameandfmt
== NULL
)
1730 len
= snprintf(buf
, bufsize
, cur_ptr
->nameandfmt
,
1731 read_rtn(arg0
, arg1
, cur_ptr
->offset
));
1732 /* check for snprintf overflow or error */
1733 if (len
< 0 || (uint32
)len
>= bufsize
)
1744 bcm_mkiovar(char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
1748 len
= strlen(name
) + 1;
1750 if ((len
+ datalen
) > buflen
)
1753 strncpy(buf
, name
, buflen
);
1755 /* append data onto the end of the name string */
1756 memcpy(&buf
[len
], data
, datalen
);
1762 #ifndef BCMROMOFFLOAD
1764 /* Quarter dBm units to mW
1765 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1766 * Table is offset so the last entry is largest mW value that fits in
1770 #define QDBM_OFFSET 153 /* Offset for first entry */
1771 #define QDBM_TABLE_LEN 40 /* Table size */
1773 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1774 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1776 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1778 /* Largest mW value that will round down to the last table entry,
1779 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1780 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1782 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1784 static const uint16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
1785 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1786 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1787 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1788 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1789 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1790 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1794 BCMROMFN(bcm_qdbm_to_mw
)(uint8 qdbm
)
1797 int idx
= qdbm
- QDBM_OFFSET
;
1799 if (idx
> QDBM_TABLE_LEN
) {
1800 /* clamp to max uint16 mW value */
1804 /* scale the qdBm index up to the range of the table 0-40
1805 * where an offset of 40 qdBm equals a factor of 10 mW.
1812 /* return the mW value scaled down to the correct factor of 10,
1813 * adding in factor/2 to get proper rounding.
1815 return ((nqdBm_to_mW_map
[idx
] + factor
/2) / factor
);
1819 BCMROMFN(bcm_mw_to_qdbm
)(uint16 mw
)
1826 /* handle boundary case */
1830 offset
= QDBM_OFFSET
;
1832 /* move mw into the range of the table */
1833 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
1838 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
-1; qdbm
++) {
1839 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+1] -
1840 nqdBm_to_mW_map
[qdbm
])/2;
1841 if (mw_uint
< boundary
) break;
1844 qdbm
+= (uint8
)offset
;
1851 BCMROMFN(bcm_bitcount
)(uint8
*bitmap
, uint length
)
1853 uint bitcount
= 0, i
;
1855 for (i
= 0; i
< length
; i
++) {
1865 #endif /* !BCMROMOFFLOAD */
1869 /* Initialization of bcmstrbuf structure */
1871 bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
1873 b
->origsize
= b
->size
= size
;
1874 b
->origbuf
= b
->buf
= buf
;
1877 /* Buffer sprintf wrapper to guard against buffer overflow */
1879 bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
1885 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
1887 /* Non Ansi C99 compliant returns -1,
1888 * Ansi compliant return r >= b->size,
1889 * bcmstdlib returns 0, handle all
1891 if ((r
== -1) || (r
>= (int)b
->size
) || (r
== 0)) {
1902 #endif /* BCMDRIVER */