2 * Driver O/S-independent utility routines
4 * Copyright (C) 1999-2015, Broadcom Corporation
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 * $Id: bcmutils.c 551820 2015-04-24 08:43:23Z $
35 #else /* !BCMDRIVER */
41 #if defined(BCMEXTSUP)
49 #endif /* !BCMDRIVER */
51 #include <bcmendian.h>
53 #include <proto/ethernet.h>
54 #include <proto/vlan.h>
55 #include <proto/bcmip.h>
56 #include <proto/802.1d.h>
57 #include <proto/802.11.h>
60 void *_bcmutils_dummy_fn = NULL;
68 /* copy a pkt buffer chain into a buffer */
70 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
75 len = 4096; /* "infinite" */
77 /* skip 'offset' bytes */
78 for (; p && offset; p = PKTNEXT(osh, p)) {
79 if (offset < (uint)PKTLEN(osh, p))
81 offset -= PKTLEN(osh, p);
88 for (; p && len; p = PKTNEXT(osh, p)) {
89 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
90 bcopy(PKTDATA(osh, p) + offset, buf, n);
100 /* copy a buffer into a pkt buffer chain */
102 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
107 /* skip 'offset' bytes */
108 for (; p && offset; p = PKTNEXT(osh, p)) {
109 if (offset < (uint)PKTLEN(osh, p))
111 offset -= PKTLEN(osh, p);
118 for (; p && len; p = PKTNEXT(osh, p)) {
119 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
120 bcopy(buf, PKTDATA(osh, p) + offset, n);
132 /* return total length of buffer chain */
134 pkttotlen(osl_t *osh, void *p)
140 for (; p; p = PKTNEXT(osh, p)) {
141 len = PKTLEN(osh, p);
144 if (BCMLFRAG_ENAB()) {
145 if (PKTISFRAG(osh, p)) {
146 total += PKTFRAGTOTLEN(osh, p);
155 /* return the last buffer of chained pkt */
157 pktlast(osl_t *osh, void *p)
159 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
165 /* count segments of a chained packet */
167 pktsegcnt(osl_t *osh, void *p)
171 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
174 if (BCMLFRAG_ENAB()) {
175 if (PKTISFRAG(osh, p)) {
176 cnt += PKTFRAGTOTNUM(osh, p);
186 /* count segments of a chained packet */
188 pktsegcnt_war(osl_t *osh, void *p)
192 uint len, remain, align64;
194 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
196 len = PKTLEN(osh, p);
198 pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */
199 /* Check for page boundary straddle (2048B) */
200 if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
203 align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */
204 align64 = (64 - align64) & 0x3f;
205 len -= align64; /* bytes from aligned 64B to end */
206 /* if aligned to 128B, check for MOD 128 between 1 to 4B */
208 if (remain > 0 && remain <= 4)
209 cnt++; /* add extra seg */
217 pktdataoffset(osl_t *osh, void *p, uint offset)
219 uint total = pkttotlen(osh, p);
220 uint pkt_off = 0, len = 0;
221 uint8 *pdata = (uint8 *) PKTDATA(osh, p);
226 for (; p; p = PKTNEXT(osh, p)) {
227 pdata = (uint8 *) PKTDATA(osh, p);
228 pkt_off = offset - len;
229 len += PKTLEN(osh, p);
233 return (uint8*) (pdata+pkt_off);
237 /* given a offset in pdata, find the pkt seg hdr */
239 pktoffset(osl_t *osh, void *p, uint offset)
241 uint total = pkttotlen(osh, p);
247 for (; p; p = PKTNEXT(osh, p)) {
248 len += PKTLEN(osh, p);
256 * osl multiple-precedence packet queue
257 * hi_prec is always >= the number of the highest non-empty precedence
260 pktq_penq(struct pktq *pq, int prec, void *p)
264 ASSERT(prec >= 0 && prec < pq->num_prec);
265 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
267 ASSERT(!pktq_full(pq));
268 ASSERT(!pktq_pfull(pq, prec));
273 PKTSETLINK(q->tail, p);
282 if (pq->hi_prec < prec)
283 pq->hi_prec = (uint8)prec;
289 pktq_penq_head(struct pktq *pq, int prec, void *p)
293 ASSERT(prec >= 0 && prec < pq->num_prec);
294 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
296 ASSERT(!pktq_full(pq));
297 ASSERT(!pktq_pfull(pq, prec));
304 PKTSETLINK(p, q->head);
310 if (pq->hi_prec < prec)
311 pq->hi_prec = (uint8)prec;
317 pktq_pdeq(struct pktq *pq, int prec)
322 ASSERT(prec >= 0 && prec < pq->num_prec);
326 if ((p = q->head) == NULL)
329 if ((q->head = PKTLINK(p)) == NULL)
342 pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p)
347 ASSERT(prec >= 0 && prec < pq->num_prec);
354 if ((p = PKTLINK(prev_p)) == NULL)
361 PKTSETLINK(prev_p, PKTLINK(p));
368 pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg)
371 void *p, *prev = NULL;
373 ASSERT(prec >= 0 && prec < pq->num_prec);
379 if (fn == NULL || (*fn)(p, arg)) {
390 if ((q->head = PKTLINK(p)) == NULL) {
394 PKTSETLINK(prev, PKTLINK(p));
410 pktq_pdeq_tail(struct pktq *pq, int prec)
415 ASSERT(prec >= 0 && prec < pq->num_prec);
419 if ((p = q->head) == NULL)
422 for (prev = NULL; p != q->tail; p = PKTLINK(p))
426 PKTSETLINK(prev, NULL);
439 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
442 void *p, *prev = NULL;
447 if (fn == NULL || (*fn)(p, arg)) {
448 bool head = (p == q->head);
450 q->head = PKTLINK(p);
452 PKTSETLINK(prev, PKTLINK(p));
454 PKTFREE(osh, p, dir);
457 p = (head ? q->head : PKTLINK(prev));
464 if (q->head == NULL) {
471 pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
476 ASSERT(prec >= 0 && prec < pq->num_prec);
483 if (q->head == pktbuf) {
484 if ((q->head = PKTLINK(pktbuf)) == NULL)
487 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
492 PKTSETLINK(p, PKTLINK(pktbuf));
493 if (q->tail == pktbuf)
499 PKTSETLINK(pktbuf, NULL);
504 pktq_init(struct pktq *pq, int num_prec, int max_len)
508 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
510 /* pq is variable size; only zero out what's requested */
511 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
513 pq->num_prec = (uint16)num_prec;
515 pq->max = (uint16)max_len;
517 for (prec = 0; prec < num_prec; prec++)
518 pq->q[prec].max = pq->max;
522 pktq_set_max_plen(struct pktq *pq, int prec, int max_len)
524 ASSERT(prec >= 0 && prec < pq->num_prec);
526 if (prec < pq->num_prec)
527 pq->q[prec].max = (uint16)max_len;
531 pktq_deq(struct pktq *pq, int *prec_out)
540 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
545 if ((p = q->head) == NULL)
548 if ((q->head = PKTLINK(p)) == NULL)
564 pktq_deq_tail(struct pktq *pq, int *prec_out)
573 for (prec = 0; prec < pq->hi_prec; prec++)
574 if (pq->q[prec].head)
579 if ((p = q->head) == NULL)
582 for (prev = NULL; p != q->tail; p = PKTLINK(p))
586 PKTSETLINK(prev, NULL);
604 pktq_peek(struct pktq *pq, int *prec_out)
611 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
617 return (pq->q[prec].head);
621 pktq_peek_tail(struct pktq *pq, int *prec_out)
628 for (prec = 0; prec < pq->hi_prec; prec++)
629 if (pq->q[prec].head)
635 return (pq->q[prec].tail);
639 pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
643 /* Optimize flush, if pktq len = 0, just return.
644 * pktq len of 0 means pktq's prec q's are all empty.
650 for (prec = 0; prec < pq->num_prec; prec++)
651 pktq_pflush(osh, pq, prec, dir, fn, arg);
653 ASSERT(pq->len == 0);
656 /* Return sum of lengths of a specific set of precedences */
658 pktq_mlen(struct pktq *pq, uint prec_bmp)
664 for (prec = 0; prec <= pq->hi_prec; prec++)
665 if (prec_bmp & (1 << prec))
666 len += pq->q[prec].len;
671 /* Priority peek from a specific set of precedences */
673 pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out)
683 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
686 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
692 if ((p = q->head) == NULL)
700 /* Priority dequeue from a specific set of precedences */
702 pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
711 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
714 while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0))
720 if ((p = q->head) == NULL)
723 if ((q->head = PKTLINK(p)) == NULL)
738 #endif /* BCMDRIVER */
740 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
741 const unsigned char bcm_ctype[] = {
743 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
744 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
746 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
747 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
748 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
749 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
750 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
751 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
752 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
753 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
754 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
755 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
756 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
757 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
758 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
759 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
760 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
761 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
763 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
764 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
765 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
766 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
767 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
768 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
769 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
770 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
771 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
772 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
773 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
774 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
775 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
779 bcm_strtoul(const char *cp, char **endp, uint base)
781 ulong result, last_result = 0, value;
786 while (bcm_isspace(*cp))
791 else if (cp[0] == '-') {
798 if ((cp[1] == 'x') || (cp[1] == 'X')) {
807 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
813 while (bcm_isxdigit(*cp) &&
814 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
815 result = result*base + value;
816 /* Detected overflow */
817 if (result < last_result && !minus)
819 last_result = result;
824 result = (ulong)(-(long)result);
827 *endp = DISCARD_QUAL(cp, char);
833 bcm_atoi(const char *s)
835 return (int)bcm_strtoul(s, NULL, 10);
838 /* return pointer to location of substring 'needle' in 'haystack' */
840 bcmstrstr(const char *haystack, const char *needle)
845 if ((haystack == NULL) || (needle == NULL))
846 return DISCARD_QUAL(haystack, char);
848 nlen = strlen(needle);
849 len = strlen(haystack) - nlen + 1;
851 for (i = 0; i < len; i++)
852 if (memcmp(needle, &haystack[i], nlen) == 0)
853 return DISCARD_QUAL(&haystack[i], char);
858 bcmstrcat(char *dest, const char *src)
862 p = dest + strlen(dest);
864 while ((*p++ = *src++) != '\0')
871 bcmstrncat(char *dest, const char *src, uint size)
876 p = dest + strlen(dest);
879 while (p != endp && (*p++ = *src++) != '\0')
886 /****************************************************************************
887 * Function: bcmstrtok
890 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
891 * but allows strToken() to be used by different strings or callers at the same
892 * time. Each call modifies '*string' by substituting a NULL character for the
893 * first delimiter that is encountered, and updates 'string' to point to the char
894 * after the delimiter. Leading delimiters are skipped.
897 * string (mod) Ptr to string ptr, updated by token.
898 * delimiters (in) Set of delimiter characters.
899 * tokdelim (out) Character that delimits the returned token. (May
900 * be set to NULL if token delimiter is not required).
902 * Returns: Pointer to the next token found. NULL when no more tokens are found.
903 *****************************************************************************
906 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
909 unsigned long map[8];
913 if (tokdelim != NULL) {
914 /* Prime the token delimiter */
918 /* Clear control map */
919 for (count = 0; count < 8; count++) {
923 /* Set bits in delimiter table */
925 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
927 while (*delimiters++);
929 str = (unsigned char*)*string;
931 /* Find beginning of token (skip over leading delimiters). Note that
932 * there is no token iff this loop sets str to point to the terminal
933 * null (*str == '\0')
935 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
939 nextoken = (char*)str;
941 /* Find the end of the token. If it is not the end of the string,
944 for (; *str; str++) {
945 if (map[*str >> 5] & (1 << (*str & 31))) {
946 if (tokdelim != NULL) {
955 *string = (char*)str;
957 /* Determine if a token has been found. */
958 if (nextoken == (char *) str) {
967 #define xToLower(C) \
968 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
971 /****************************************************************************
972 * Function: bcmstricmp
974 * Purpose: Compare to strings case insensitively.
976 * Parameters: s1 (in) First string to compare.
977 * s2 (in) Second string to compare.
979 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
980 * t1 > t2, when ignoring case sensitivity.
981 *****************************************************************************
984 bcmstricmp(const char *s1, const char *s2)
991 if (dc < sc) return -1;
992 if (dc > sc) return 1;
997 if (*s1 && !*s2) return 1;
998 if (!*s1 && *s2) return -1;
1003 /****************************************************************************
1004 * Function: bcmstrnicmp
1006 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
1009 * Parameters: s1 (in) First string to compare.
1010 * s2 (in) Second string to compare.
1011 * cnt (in) Max characters to compare.
1013 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1014 * t1 > t2, when ignoring case sensitivity.
1015 *****************************************************************************
1018 bcmstrnicmp(const char* s1, const char* s2, int cnt)
1022 while (*s2 && *s1 && cnt) {
1025 if (dc < sc) return -1;
1026 if (dc > sc) return 1;
1033 if (*s1 && !*s2) return 1;
1034 if (!*s1 && *s2) return -1;
1038 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
1040 bcm_ether_atoe(const char *p, struct ether_addr *ea)
1046 ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
1048 if (!*p++ || i == 6)
1056 bcm_atoipv4(const char *p, struct ipv4_addr *ip)
1062 ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0);
1063 if (*c++ != '.' || i == IPV4_ADDR_LEN)
1067 return (i == IPV4_ADDR_LEN);
1069 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
1072 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
1073 /* registry routine buffer preparation utility functions:
1074 * parameter order is like strncpy, but returns count
1075 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
1078 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
1086 /* wbuflen is in bytes */
1087 wbuflen /= sizeof(ushort);
1089 for (i = 0; i < wbuflen; ++i) {
1092 *abuf++ = (char) *wbuf++;
1099 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
1102 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
1104 static const char hex[] =
1106 '0', '1', '2', '3', '4', '5', '6', '7',
1107 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1109 const uint8 *octet = ea->octet;
1113 for (i = 0; i < 6; i++, octet++) {
1114 *p++ = hex[(*octet >> 4) & 0xf];
1115 *p++ = hex[*octet & 0xf];
1125 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
1127 snprintf(buf, 16, "%d.%d.%d.%d",
1128 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
1133 bcm_ipv6_ntoa(void *ipv6, char *buf)
1135 /* Implementing RFC 5952 Sections 4 + 5 */
1136 /* Not thoroughly tested */
1138 uint16 *a = &tmp[0];
1140 int i, i_max = -1, cnt = 0, cnt_max = 1;
1142 memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
1144 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
1146 if (cnt > cnt_max) {
1154 if (cnt > cnt_max) {
1159 /* IPv4-translated: ::ffff:0:a.b.c.d */
1160 ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
1161 /* IPv4-mapped: ::ffff:a.b.c.d */
1162 (cnt_max == 5 && a[5] == 0xffff)))
1163 a4 = (uint8*) (a + 6);
1165 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
1166 if ((uint8*) (a + i) == a4) {
1167 snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
1169 } else if (i == i_max) {
1177 p += snprintf(p, 8, "%x", ntoh16(a[i]));
1190 for (i = 0; i < ms; i++) {
1199 #if defined(DHD_DEBUG)
1200 /* pretty hex print a pkt buffer chain */
1202 prpkt(const char *msg, osl_t *osh, void *p0)
1206 if (msg && (msg[0] != '\0'))
1207 printf("%s:\n", msg);
1209 for (p = p0; p; p = PKTNEXT(osh, p))
1210 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
1214 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
1215 * Also updates the inplace vlan tag if requested.
1216 * For debugging, it returns an indication of what it did.
1219 pktsetprio(void *pkt, bool update_vtag)
1221 struct ether_header *eh;
1222 struct ethervlan_header *evh;
1227 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
1228 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
1230 eh = (struct ether_header *) pktdata;
1232 if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
1234 int vlan_prio, dscp_prio = 0;
1236 evh = (struct ethervlan_header *)eh;
1238 vlan_tag = ntoh16(evh->vlan_tag);
1239 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
1241 if (evh->ether_type == hton16(ETHER_TYPE_IP)) {
1242 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
1243 uint8 tos_tc = IP_TOS46(ip_body);
1244 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
1247 /* DSCP priority gets precedence over 802.1P (vlan tag) */
1248 if (dscp_prio != 0) {
1249 priority = dscp_prio;
1250 rc |= PKTPRIO_VDSCP;
1252 priority = vlan_prio;
1256 * If the DSCP priority is not the same as the VLAN priority,
1257 * then overwrite the priority field in the vlan tag, with the
1258 * DSCP priority value. This is required for Linux APs because
1259 * the VLAN driver on Linux, overwrites the skb->priority field
1260 * with the priority value in the vlan tag
1262 if (update_vtag && (priority != vlan_prio)) {
1263 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
1264 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
1265 evh->vlan_tag = hton16(vlan_tag);
1268 #ifdef DHD_LOSSLESS_ROAMING
1269 } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
1270 priority = PRIO_8021D_NC;
1272 #endif /* DHD_LOSSLESS_ROAMING */
1273 } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) {
1274 uint8 *ip_body = pktdata + sizeof(struct ether_header);
1275 uint8 tos_tc = IP_TOS46(ip_body);
1276 uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
1279 priority = PRIO_8021D_VO;
1284 priority = PRIO_8021D_CL;
1292 priority = PRIO_8021D_EE;
1295 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
1302 ASSERT(priority >= 0 && priority <= MAXPRIO);
1303 PKTSETPRIO(pkt, priority);
1304 return (rc | priority);
1307 /* lookup user priority for specified DSCP */
1309 dscp2up(uint8 *up_table, uint8 dscp)
1313 /* lookup up from table if parameters valid */
1314 if (up_table != NULL && dscp < UP_TABLE_MAX) {
1315 up = up_table[dscp];
1318 /* 255 is unused value so return up from dscp */
1320 up = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
1326 /* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
1328 pktsetprio_qms(void *pkt, int8* up_table, bool update_vtag)
1337 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
1338 pktlen = PKTLEN(OSH_NULL, pkt);
1340 if (pktgetdscp(pktdata, pktlen, &dscp)) {
1342 up = dscp2up(up_table, dscp);
1343 PKTSETPRIO(pkt, up);
1344 printf("dscp=%d, up=%d\n", dscp, up);
1350 return pktsetprio(pkt, update_vtag);
1354 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
1357 pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
1359 struct ether_header *eh;
1360 struct ethervlan_header *evh;
1364 /* minimum length is ether header and IP header */
1365 if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
1368 eh = (struct ether_header *) pktdata;
1370 if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
1371 ip_body = pktdata + sizeof(struct ether_header);
1372 *dscp = IP_DSCP46(ip_body);
1375 else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
1376 evh = (struct ethervlan_header *)eh;
1378 /* minimum length is ethervlan header and IP header */
1379 if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
1380 evh->ether_type == HTON16(ETHER_TYPE_IP)) {
1381 ip_body = pktdata + sizeof(struct ethervlan_header);
1382 *dscp = IP_DSCP46(ip_body);
1391 static char bcm_undeferrstr[32];
1392 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1394 /* Convert the error codes into related error strings */
1396 bcmerrorstr(int bcmerror)
1398 /* check if someone added a bcmerror code but forgot to add errorstring */
1399 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
1401 if (bcmerror > 0 || bcmerror < BCME_LAST) {
1402 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
1403 return bcm_undeferrstr;
1406 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1408 return bcmerrorstrtable[-bcmerror];
1413 /* iovar table lookup */
1415 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1417 const bcm_iovar_t *vi;
1418 const char *lookup_name;
1420 /* skip any ':' delimited option prefixes */
1421 lookup_name = strrchr(name, ':');
1422 if (lookup_name != NULL)
1427 ASSERT(table != NULL);
1429 for (vi = table; vi->name; vi++) {
1430 if (!strcmp(vi->name, lookup_name))
1433 /* ran to end of table */
1435 return NULL; /* var name not found */
1439 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1443 /* length check on io buf */
1452 /* all integers are int32 sized args at the ioctl interface */
1453 if (len < (int)sizeof(int)) {
1454 bcmerror = BCME_BUFTOOSHORT;
1459 /* buffer must meet minimum length requirement */
1460 if (len < vi->minlen) {
1461 bcmerror = BCME_BUFTOOSHORT;
1467 /* Cannot return nil... */
1468 bcmerror = BCME_UNSUPPORTED;
1470 /* Set is an action w/o parameters */
1471 bcmerror = BCME_BUFTOOLONG;
1476 /* unknown type for length check in iovar info */
1478 bcmerror = BCME_UNSUPPORTED;
1484 #endif /* BCMDRIVER */
1488 bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst)
1490 uint8 *new_dst = dst;
1491 bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst;
1493 /* dst buffer should always be valid */
1496 /* data len must be within valid range */
1497 ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE));
1499 /* source data buffer pointer should be valid, unless datalen is 0
1500 * meaning no data with this TLV
1502 ASSERT((data != NULL) || (datalen == 0));
1504 /* only do work if the inputs are valid
1505 * - must have a dst to write to AND
1506 * - datalen must be within range AND
1507 * - the source data pointer must be non-NULL if datalen is non-zero
1508 * (this last condition detects datalen > 0 with a NULL data pointer)
1510 if ((dst != NULL) &&
1511 ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
1512 ((data != NULL) || (datalen == 0))) {
1514 /* write type, len fields */
1515 dst_tlv->id = (uint8)type;
1516 dst_tlv->len = (uint8)datalen;
1518 /* if data is present, copy to the output buffer and update
1519 * pointer to output buffer
1523 memcpy(dst_tlv->data, data, datalen);
1526 /* update the output destination poitner to point past
1529 new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
1536 bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen)
1538 uint8 *new_dst = dst;
1540 if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) {
1542 /* if len + tlv hdr len is more than destlen, don't do anything
1543 * just return the buffer untouched
1545 if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) {
1547 new_dst = bcm_write_tlv(type, data, datalen, dst);
1555 bcm_copy_tlv(const void *src, uint8 *dst)
1557 uint8 *new_dst = dst;
1558 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1564 totlen = BCM_TLV_HDR_SIZE + src_tlv->len;
1565 memcpy(dst, src_tlv, totlen);
1566 new_dst = dst + totlen;
1573 uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen)
1575 uint8 *new_dst = dst;
1576 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1580 if (bcm_valid_tlv(src_tlv, dst_maxlen)) {
1581 new_dst = bcm_copy_tlv(src, dst);
1589 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
1590 /*******************************************************************************
1593 * Computes a crc8 over the input data using the polynomial:
1595 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1597 * The caller provides the initial value (either CRC8_INIT_VALUE
1598 * or the previous returned value) to allow for processing of
1599 * discontiguous blocks of data. When generating the CRC the
1600 * caller is responsible for complementing the final return value
1601 * and inserting it into the byte stream. When checking, a final
1602 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1604 * Reference: Dallas Semiconductor Application Note 27
1605 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1606 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1607 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1609 * ****************************************************************************
1612 static const uint8 crc8_table[256] = {
1613 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1614 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1615 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1616 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1617 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1618 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1619 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1620 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1621 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1622 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1623 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1624 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1625 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1626 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1627 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1628 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1629 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1630 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1631 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1632 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1633 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1634 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1635 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1636 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1637 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1638 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1639 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1640 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1641 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1642 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1643 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1644 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1647 #define CRC_INNER_LOOP(n, c, x) \
1648 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1652 uint8 *pdata, /* pointer to array of data to process */
1653 uint nbytes, /* number of input data bytes to process */
1654 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1657 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1658 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1660 while (nbytes-- > 0)
1661 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1666 /*******************************************************************************
1669 * Computes a crc16 over the input data using the polynomial:
1671 * x^16 + x^12 +x^5 + 1
1673 * The caller provides the initial value (either CRC16_INIT_VALUE
1674 * or the previous returned value) to allow for processing of
1675 * discontiguous blocks of data. When generating the CRC the
1676 * caller is responsible for complementing the final return value
1677 * and inserting it into the byte stream. When checking, a final
1678 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1680 * Reference: Dallas Semiconductor Application Note 27
1681 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1682 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1683 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1685 * ****************************************************************************
1688 static const uint16 crc16_table[256] = {
1689 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1690 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1691 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1692 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1693 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1694 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1695 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1696 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1697 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1698 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1699 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1700 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1701 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1702 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1703 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1704 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1705 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1706 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1707 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1708 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1709 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1710 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1711 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1712 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1713 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1714 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1715 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1716 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1717 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1718 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1719 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1720 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1725 uint8 *pdata, /* pointer to array of data to process */
1726 uint nbytes, /* number of input data bytes to process */
1727 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1730 while (nbytes-- > 0)
1731 CRC_INNER_LOOP(16, crc, *pdata++);
1735 static const uint32 crc32_table[256] = {
1736 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1737 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1738 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1739 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1740 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1741 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1742 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1743 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1744 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1745 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1746 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1747 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1748 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1749 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1750 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1751 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1752 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1753 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1754 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1755 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1756 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1757 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1758 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1759 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1760 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1761 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1762 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1763 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1764 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1765 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1766 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1767 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1768 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1769 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1770 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1771 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1772 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1773 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1774 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1775 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1776 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1777 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1778 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1779 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1780 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1781 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1782 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1783 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1784 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1785 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1786 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1787 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1788 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1789 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1790 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1791 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1792 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1793 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1794 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1795 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1796 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1797 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1798 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1799 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1803 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
1804 * accumulating over multiple pieces.
1807 hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
1810 pend = pdata + nbytes;
1811 while (pdata < pend)
1812 CRC_INNER_LOOP(32, crc, *pdata++);
1818 #define CLEN 1499 /* CRC Length */
1819 #define CBUFSIZ (CLEN+4)
1820 #define CNBUFS 5 /* # of bufs */
1829 uint32 crc32tv[CNBUFS] =
1830 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1832 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1834 /* step through all possible alignments */
1835 for (l = 0; l <= 4; l++) {
1836 for (j = 0; j < CNBUFS; j++) {
1838 for (k = 0; k < len[j]; k++)
1839 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1842 for (j = 0; j < CNBUFS; j++) {
1843 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1844 ASSERT(crcr == crc32tv[j]);
1848 MFREE(buf, CBUFSIZ*CNBUFS);
1854 * Advance from the current 1-byte tag/1-byte length/variable-length value
1855 * triple, to the next, returning a pointer to the next.
1856 * If the current or next TLV is invalid (does not fit in given buffer length),
1858 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1859 * by the TLV parameter's length if it is valid.
1862 bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1866 /* validate current elt */
1867 if (!bcm_valid_tlv(elt, *buflen)) {
1871 /* advance to next elt */
1873 elt = (bcm_tlv_t*)(elt->data + len);
1874 *buflen -= (TLV_HDR_LEN + len);
1876 /* validate next elt */
1877 if (!bcm_valid_tlv(elt, *buflen)) {
1885 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1886 * triples, returning a pointer to the substring whose first element
1890 bcm_parse_tlvs(void *buf, int buflen, uint key)
1895 elt = (bcm_tlv_t*)buf;
1898 /* find tagged parameter */
1899 while (totlen >= TLV_HDR_LEN) {
1902 /* validate remaining totlen */
1903 if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
1908 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
1909 totlen -= (len + TLV_HDR_LEN);
1916 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1917 * triples, returning a pointer to the substring whose first element
1918 * matches tag. Stop parsing when we see an element whose ID is greater
1919 * than the target key.
1922 bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1927 elt = (bcm_tlv_t*)buf;
1930 /* find tagged parameter */
1931 while (totlen >= TLV_HDR_LEN) {
1935 /* Punt if we start seeing IDs > than target key */
1940 /* validate remaining totlen */
1941 if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
1945 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
1946 totlen -= (len + TLV_HDR_LEN);
1950 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
1952 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1955 bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len)
1961 if (len < 2 || !buf)
1966 for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) {
1967 bit = bd->bitfield[i].bit;
1968 if ((flags & mask) == bit) {
1969 if (len > (int)strlen(name)) {
1970 slen = strlen(name);
1971 strncpy(buf, name, slen+1);
1980 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1985 int slen = 0, nlen = 0;
1989 if (len < 2 || !buf)
1994 for (i = 0; flags != 0; i++) {
1997 if (bit == 0 && flags != 0) {
1998 /* print any unnamed bits */
1999 snprintf(hexstr, 16, "0x%X", flags);
2001 flags = 0; /* exit loop */
2002 } else if ((flags & bit) == 0)
2005 nlen = strlen(name);
2007 /* count btwn flag space */
2010 /* need NULL char as well */
2013 /* copy NULL char but don't count it */
2014 strncpy(p, name, nlen + 1);
2016 /* copy btwn flag space and NULL char */
2018 p += snprintf(p, 2, " ");
2021 /* indicate the str was too short */
2023 p += snprintf(p, 2, ">");
2026 return (int)(p - buf);
2029 /* print bytes formatted as hex to a string. return the resulting string length */
2031 bcm_format_hex(char *str, const void *bytes, int len)
2035 const uint8 *src = (const uint8*)bytes;
2037 for (i = 0; i < len; i++) {
2038 p += snprintf(p, 3, "%02X", *src);
2041 return (int)(p - str);
2045 /* pretty hex print a contiguous buffer */
2047 prhex(const char *msg, uchar *buf, uint nbytes)
2050 int len = sizeof(line);
2054 if (msg && (msg[0] != '\0'))
2055 printf("%s:\n", msg);
2058 for (i = 0; i < nbytes; i++) {
2060 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
2065 nchar = snprintf(p, len, "%02x ", buf[i]);
2071 printf("%s\n", line); /* flush line */
2077 /* flush last partial line */
2079 printf("%s\n", line);
2082 static const char *crypto_algo_names[] = {
2114 bcm_crypto_algo_name(uint algo)
2116 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
2121 bcm_chipname(uint chipid, char *buf, uint len)
2125 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
2126 snprintf(buf, len, fmt, chipid);
2130 /* Produce a human-readable string for boardrev */
2132 bcm_brev_str(uint32 brev, char *buf)
2135 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
2137 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
2142 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2144 /* dump large strings to console */
2153 max_len = BUFSIZE_TODUMP_ATONCE;
2155 while (len > max_len) {
2157 buf[max_len] = '\0';
2164 /* print the remaining string */
2165 printf("%s\n", buf);
2169 /* routine to dump fields in a fileddesc structure */
2171 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
2172 char *buf, uint32 bufsize)
2176 struct fielddesc *cur_ptr;
2179 cur_ptr = fielddesc_array;
2181 while (bufsize > 1) {
2182 if (cur_ptr->nameandfmt == NULL)
2184 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
2185 read_rtn(arg0, arg1, cur_ptr->offset));
2186 /* check for snprintf overflow or error */
2187 if (len < 0 || (uint32)len >= bufsize)
2198 bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
2202 len = strlen(name) + 1;
2204 if ((len + datalen) > buflen)
2207 strncpy(buf, name, buflen);
2209 /* append data onto the end of the name string */
2211 memcpy(&buf[len], data, datalen);
2218 /* Quarter dBm units to mW
2219 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
2220 * Table is offset so the last entry is largest mW value that fits in
2224 #define QDBM_OFFSET 153 /* Offset for first entry */
2225 #define QDBM_TABLE_LEN 40 /* Table size */
2227 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
2228 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
2230 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
2232 /* Largest mW value that will round down to the last table entry,
2233 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
2234 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
2236 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
2238 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
2239 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
2240 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
2241 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
2242 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
2243 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
2244 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
2248 bcm_qdbm_to_mw(uint8 qdbm)
2251 int idx = qdbm - QDBM_OFFSET;
2253 if (idx >= QDBM_TABLE_LEN) {
2254 /* clamp to max uint16 mW value */
2258 /* scale the qdBm index up to the range of the table 0-40
2259 * where an offset of 40 qdBm equals a factor of 10 mW.
2266 /* return the mW value scaled down to the correct factor of 10,
2267 * adding in factor/2 to get proper rounding.
2269 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
2273 bcm_mw_to_qdbm(uint16 mw)
2280 /* handle boundary case */
2284 offset = QDBM_OFFSET;
2286 /* move mw into the range of the table */
2287 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
2292 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
2293 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
2294 nqdBm_to_mW_map[qdbm])/2;
2295 if (mw_uint < boundary) break;
2298 qdbm += (uint8)offset;
2305 bcm_bitcount(uint8 *bitmap, uint length)
2307 uint bitcount = 0, i;
2309 for (i = 0; i < length; i++) {
2321 /* Initialization of bcmstrbuf structure */
2323 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
2325 b->origsize = b->size = size;
2326 b->origbuf = b->buf = buf;
2329 /* Buffer sprintf wrapper to guard against buffer overflow */
2331 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
2338 r = vsnprintf(b->buf, b->size, fmt, ap);
2340 /* Non Ansi C99 compliant returns -1,
2341 * Ansi compliant return r >= b->size,
2342 * bcmstdlib returns 0, handle all
2344 /* r == 0 is also the case when strlen(fmt) is zero.
2345 * typically the case when "" is passed as argument.
2347 if ((r == -1) || (r >= (int)b->size)) {
2360 bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len)
2364 if (msg != NULL && msg[0] != '\0')
2365 bcm_bprintf(b, "%s", msg);
2366 for (i = 0; i < len; i ++)
2367 bcm_bprintf(b, "%02X", buf[i]);
2369 bcm_bprintf(b, "\n");
2373 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
2377 for (i = 0; i < num_bytes; i++) {
2379 if (num[i] >= amount)
2386 bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
2390 for (i = nbytes - 1; i >= 0; i--) {
2391 if (arg1[i] != arg2[i])
2392 return (arg1[i] - arg2[i]);
2398 bcm_print_bytes(const char *name, const uchar *data, int len)
2403 printf("%s: %d \n", name ? name : "", len);
2404 for (i = 0; i < len; i++) {
2405 printf("%02x ", *data++);
2407 if (per_line == 16) {
2415 /* Look for vendor-specific IE with specified OUI and optional type */
2417 bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len)
2422 ie = (bcm_tlv_t*)tlvs;
2424 /* make sure we are looking at a valid IE */
2425 if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
2429 /* Walk through the IEs looking for an OUI match */
2432 if ((ie->id == DOT11_MNG_PROPR_ID) &&
2433 (ie_len >= (DOT11_OUI_LEN + type_len)) &&
2434 !bcmp(ie->data, voui, DOT11_OUI_LEN))
2436 /* compare optional type */
2437 if (type_len == 0 ||
2438 !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
2439 return (ie); /* a match */
2442 } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
2447 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
2448 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
2449 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
2452 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
2456 char *endp = buf + SSID_FMT_BUF_LEN;
2458 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
2460 for (i = 0; i < ssid_len; i++) {
2465 } else if (bcm_isprint((uchar)c)) {
2468 p += snprintf(p, (endp - p), "\\x%02X", c);
2474 return (int)(p - buf);
2478 #endif /* BCMDRIVER */
2481 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
2482 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
2483 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
2484 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
2488 process_nvram_vars(char *varbuf, unsigned int len)
2493 unsigned int buf_len, n;
2494 unsigned int pad = 0;
2498 findNewline = FALSE;
2501 for (n = 0; n < len; n++) {
2502 if (varbuf[n] == '\r')
2504 if (findNewline && varbuf[n] != '\n')
2506 findNewline = FALSE;
2507 if (varbuf[n] == '#') {
2511 if (varbuf[n] == '\n') {
2521 buf_len = (unsigned int)(dp - varbuf);
2523 pad = 4 - buf_len % 4;
2524 if (pad && (buf_len + pad <= len)) {
2529 while (dp < varbuf + n)
2535 /* calculate a * b + c */
2537 bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
2539 #define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
2541 uint32 a1, a0, b1, b0, t, cc = 0;
2551 t = (a1 * b0) << 16;
2557 t = (a0 * b1) << 16;
2568 r0 |= (cc % 2) ? 0x80000000 : 0;
2569 r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2);
2575 /* calculate a / b */
2577 bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
2579 uint32 a1 = a_high, a0 = a_low, r0 = 0;
2585 r0 += (0xffffffff / b) * a1;
2586 bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
2593 #ifndef setbit /* As in the header file */
2594 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
2595 /* Set bit in byte array. */
2597 setbit(void *array, uint bit)
2599 ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
2602 /* Clear bit in byte array. */
2604 clrbit(void *array, uint bit)
2606 ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
2609 /* Test if bit is set in byte array. */
2611 isset(const void *array, uint bit)
2613 return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY)));
2616 /* Test if bit is clear in byte array. */
2618 isclr(const void *array, uint bit)
2620 return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0);
2622 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
2626 bcm_bitprint32(const uint32 u32)
2629 for (i = NBITS(uint32) - 1; i >= 0; i--) {
2630 isbitset(u32, i) ? printf("1") : printf("0");
2631 if ((i % NBBY) == 0) printf(" ");
2638 * Hierarchical Multiword bitmap based small id allocator.
2640 * Multilevel hierarchy bitmap. (maximum 2 levels)
2641 * First hierarchy uses a multiword bitmap to identify 32bit words in the
2642 * second hierarchy that have at least a single bit set. Each bit in a word of
2643 * the second hierarchy represents a unique ID that may be allocated.
2645 * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
2646 * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
2647 * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
2648 * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
2649 * non-zero bitmap word carrying at least one free ID.
2650 * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
2651 * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
2654 * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
2655 * bits are computed each time on allocation and deallocation, requiring 4
2656 * array indexed access and 3 arithmetic operations. When not defined, a runtime
2657 * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
2658 * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
2659 * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
2660 * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
2662 * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
2663 * size is fixed. No intention to support larger than 4K indice allocation. ID
2664 * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
2665 * with savings in not having to use an indirect access, had it been dynamically
2668 #define BCM_MWBMAP_ITEMS_MAX (4 * 1024) /* May increase to 16K */
2670 #define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
2671 #define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
2672 #define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
2673 #define BCM_MWBMAP_SHIFT_OP (5)
2674 #define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
2675 #define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
2676 #define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
2678 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
2679 #define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
2680 #define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
2682 #if defined(BCM_MWBMAP_DEBUG)
2683 #define BCM_MWBMAP_AUDIT(mwb) \
2685 ASSERT((mwb != NULL) && \
2686 (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
2687 bcm_mwbmap_audit(mwb); \
2689 #define MWBMAP_ASSERT(exp) ASSERT(exp)
2690 #define MWBMAP_DBG(x) printf x
2691 #else /* !BCM_MWBMAP_DEBUG */
2692 #define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
2693 #define MWBMAP_ASSERT(exp) do {} while (0)
2694 #define MWBMAP_DBG(x)
2695 #endif /* !BCM_MWBMAP_DEBUG */
2698 typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
2699 uint16 wmaps; /* Total number of words in free wd bitmap */
2700 uint16 imaps; /* Total number of words in free id bitmap */
2701 int16 ifree; /* Count of free indices. Used only in audits */
2702 uint16 total; /* Total indices managed by multiword bitmap */
2704 void * magic; /* Audit handle parameter from user */
2706 uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */
2707 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2708 int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */
2709 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2711 uint32 id_bitmap[0]; /* Second level bitmap */
2714 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
2716 bcm_mwbmap_init(osl_t *osh, uint32 items_max)
2718 struct bcm_mwbmap * mwbmap_p;
2719 uint32 wordix, size, words, extra;
2721 /* Implementation Constraint: Uses 32bit word bitmap */
2722 MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
2723 MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
2724 MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
2725 MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
2727 ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
2729 /* Determine the number of words needed in the multiword bitmap */
2730 extra = BCM_MWBMAP_MODOP(items_max);
2731 words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
2733 /* Allocate runtime state of multiword bitmap */
2734 /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
2735 size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
2736 mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
2737 if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
2741 memset(mwbmap_p, 0, size);
2743 /* Initialize runtime multiword bitmap state */
2744 mwbmap_p->imaps = (uint16)words;
2745 mwbmap_p->ifree = (int16)items_max;
2746 mwbmap_p->total = (uint16)items_max;
2748 /* Setup magic, for use in audit of handle */
2749 mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
2751 /* Setup the second level bitmap of free indices */
2752 /* Mark all indices as available */
2753 for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
2754 mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
2755 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2756 mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
2757 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2760 /* Ensure that extra indices are tagged as un-available */
2761 if (extra) { /* fixup the free ids in last bitmap and wd_count */
2762 uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
2763 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2764 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2765 mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
2766 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2769 /* Setup the first level bitmap hierarchy */
2770 extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
2771 words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
2773 mwbmap_p->wmaps = (uint16)words;
2775 for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
2776 mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
2778 uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
2779 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2785 return BCM_MWBMAP_INVALID_HDL;
2788 /* Release resources used by multiword bitmap based small index allocator. */
2790 bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
2792 bcm_mwbmap_t * mwbmap_p;
2794 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2795 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2797 MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
2798 + (sizeof(uint32) * mwbmap_p->imaps));
2802 /* Allocate a unique small index using a multiword bitmap index allocator. */
2804 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
2806 bcm_mwbmap_t * mwbmap_p;
2807 uint32 wordix, bitmap;
2809 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2810 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2812 /* Start with the first hierarchy */
2813 for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
2815 bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
2819 uint32 count, bitix, *bitmap_p;
2821 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2823 /* clear all except trailing 1 */
2824 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
2825 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
2826 bcm_count_leading_zeros(bitmap));
2827 bitix = (BCM_MWBMAP_BITS_WORD - 1)
2828 - bcm_count_leading_zeros(bitmap); /* use asm clz */
2829 wordix = BCM_MWBMAP_MULOP(wordix) + bitix;
2831 /* Clear bit if wd count is 0, without conditional branch */
2832 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2833 count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
2834 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2835 mwbmap_p->wd_count[wordix]--;
2836 count = mwbmap_p->wd_count[wordix];
2837 MWBMAP_ASSERT(count ==
2838 (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
2839 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2840 MWBMAP_ASSERT(count >= 0);
2842 /* clear wd_bitmap bit if id_map count is 0 */
2843 bitmap = (count == 0) << bitix;
2846 "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
2847 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
2849 *bitmap_p ^= bitmap;
2851 /* Use bitix in the second hierarchy */
2852 bitmap_p = &mwbmap_p->id_bitmap[wordix];
2854 bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
2855 MWBMAP_ASSERT(bitmap != 0U);
2857 /* clear all except trailing 1 */
2858 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
2859 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
2860 bcm_count_leading_zeros(bitmap));
2861 bitix = BCM_MWBMAP_MULOP(wordix)
2862 + (BCM_MWBMAP_BITS_WORD - 1)
2863 - bcm_count_leading_zeros(bitmap); /* use asm clz */
2865 mwbmap_p->ifree--; /* decrement system wide free count */
2866 MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
2869 "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
2870 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
2873 *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
2879 ASSERT(mwbmap_p->ifree == 0);
2881 return BCM_MWBMAP_INVALID_IDX;
2884 /* Force an index at a specified position to be in use */
2886 bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
2888 bcm_mwbmap_t * mwbmap_p;
2889 uint32 count, wordix, bitmap, *bitmap_p;
2891 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2892 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2894 ASSERT(bitix < mwbmap_p->total);
2896 /* Start with second hierarchy */
2897 wordix = BCM_MWBMAP_DIVOP(bitix);
2898 bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
2899 bitmap_p = &mwbmap_p->id_bitmap[wordix];
2901 ASSERT((*bitmap_p & bitmap) == bitmap);
2903 mwbmap_p->ifree--; /* update free count */
2904 ASSERT(mwbmap_p->ifree >= 0);
2906 MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
2907 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
2910 *bitmap_p ^= bitmap; /* mark as in use */
2912 /* Update first hierarchy */
2915 wordix = BCM_MWBMAP_DIVOP(bitix);
2916 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2918 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2919 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
2920 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2921 mwbmap_p->wd_count[bitix]--;
2922 count = mwbmap_p->wd_count[bitix];
2923 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
2924 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2925 MWBMAP_ASSERT(count >= 0);
2927 bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix);
2929 MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
2930 BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
2931 (*bitmap_p) ^ bitmap, count));
2933 *bitmap_p ^= bitmap; /* mark as in use */
2938 /* Free a previously allocated index back into the multiword bitmap allocator */
2940 bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
2942 bcm_mwbmap_t * mwbmap_p;
2943 uint32 wordix, bitmap, *bitmap_p;
2945 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2946 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2948 ASSERT(bitix < mwbmap_p->total);
2950 /* Start with second level hierarchy */
2951 wordix = BCM_MWBMAP_DIVOP(bitix);
2952 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
2953 bitmap_p = &mwbmap_p->id_bitmap[wordix];
2955 ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */
2957 mwbmap_p->ifree++; /* update free count */
2958 ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
2960 MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
2961 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
2964 *bitmap_p |= bitmap; /* mark as available */
2966 /* Now update first level hierarchy */
2970 wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
2971 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
2972 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2974 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2975 mwbmap_p->wd_count[bitix]++;
2978 #if defined(BCM_MWBMAP_DEBUG)
2981 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2982 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
2983 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2984 count = mwbmap_p->wd_count[bitix];
2985 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
2986 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2988 MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
2990 MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
2991 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
2993 #endif /* BCM_MWBMAP_DEBUG */
2995 *bitmap_p |= bitmap;
3000 /* Fetch the toal number of free indices in the multiword bitmap allocator */
3002 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
3004 bcm_mwbmap_t * mwbmap_p;
3006 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3007 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3009 ASSERT(mwbmap_p->ifree >= 0);
3011 return mwbmap_p->ifree;
3014 /* Determine whether an index is inuse or free */
3016 bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
3018 bcm_mwbmap_t * mwbmap_p;
3019 uint32 wordix, bitmap;
3021 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3022 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3024 ASSERT(bitix < mwbmap_p->total);
3026 wordix = BCM_MWBMAP_DIVOP(bitix);
3027 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
3029 return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
3032 /* Debug dump a multiword bitmap allocator */
3034 bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
3037 bcm_mwbmap_t * mwbmap_p;
3039 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3040 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3042 printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p,
3043 mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
3044 for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
3045 printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
3046 bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
3049 for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
3050 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3051 count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
3052 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3053 count = mwbmap_p->wd_count[ix];
3054 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
3055 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3056 printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
3057 bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
3064 /* Audit a hierarchical multiword bitmap */
3066 bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
3068 bcm_mwbmap_t * mwbmap_p;
3069 uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
3071 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3073 for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
3075 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3077 for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
3078 if ((*bitmap_p) & (1 << bitix)) {
3079 idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
3080 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3081 count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
3082 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3083 count = mwbmap_p->wd_count[idmap_ix];
3084 ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
3085 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3086 ASSERT(count != 0U);
3092 ASSERT(free_cnt == mwbmap_p->ifree);
3094 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
3096 #endif /* BCMDRIVER */
3098 /* calculate a >> b; and returns only lower 32 bits */
3100 bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
3102 uint32 a1 = a_high, a0 = a_low, r0 = 0;
3112 a1 = a1 & ((1 << b) - 1);
3113 a1 = a1 << (32 - b);
3118 r0 = a1 >> (b - 32);
3125 /* calculate a + b where a is a 64 bit number and b is a 32 bit number */
3127 bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset)
3129 uint32 r1_lo = *r_lo;
3135 /* calculate a - b where a is a 64 bit number and b is a 32 bit number */
3137 bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset)
3139 uint32 r1_lo = *r_lo;
3145 #ifdef DEBUG_COUNTER
3146 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
3147 void counter_printlog(counter_tbl_t *ctr_tbl)
3151 if (!ctr_tbl->enabled)
3154 now = OSL_SYSUPTIME();
3156 if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) {
3158 printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print);
3160 for (i = 0; i < ctr_tbl->needed_cnt; i++) {
3161 printf(" %u", ctr_tbl->cnt[i]);
3165 ctr_tbl->prev_log_print = now;
3166 bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint));
3170 /* OSL_SYSUPTIME is not supported so no way to get time */
3171 #define counter_printlog(a) do {} while (0)
3172 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
3173 #endif /* DEBUG_COUNTER */