2 * Driver O/S-independent utility routines
4 * $Copyright Open Broadcom Corporation$
5 * $Id: bcmutils.c 496061 2014-08-11 06:14:48Z $
17 #else /* !BCMDRIVER */
23 #if defined(BCMEXTSUP)
31 #endif /* !BCMDRIVER */
33 #include <bcmendian.h>
35 #include <proto/ethernet.h>
36 #include <proto/vlan.h>
37 #include <proto/bcmip.h>
38 #include <proto/802.1d.h>
39 #include <proto/802.11.h>
42 void *_bcmutils_dummy_fn = NULL;
45 #ifdef CUSTOM_DSCP_TO_PRIO_MAPPING
46 #define CUST_IPV4_TOS_PREC_MASK 0x3F
47 #define DCSP_MAX_VALUE 64
48 /* 0:BE,1:BK,2:RESV(BK):,3:EE,:4:CL,5:VI,6:VO,7:NC */
49 int dscp2priomap[DCSP_MAX_VALUE]=
51 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, /* BK->BE */
53 2, 0, 0, 0, 0, 0, 0, 0,
54 3, 0, 0, 0, 0, 0, 0, 0,
55 4, 0, 0, 0, 0, 0, 0, 0,
56 5, 0, 0, 0, 0, 0, 0, 0,
57 6, 0, 0, 0, 0, 0, 0, 0,
58 7, 0, 0, 0, 0, 0, 0, 0
60 #endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */
67 /* copy a pkt buffer chain into a buffer */
69 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
74 len = 4096; /* "infinite" */
76 /* skip 'offset' bytes */
77 for (; p && offset; p = PKTNEXT(osh, p)) {
78 if (offset < (uint)PKTLEN(osh, p))
80 offset -= PKTLEN(osh, p);
87 for (; p && len; p = PKTNEXT(osh, p)) {
88 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
89 bcopy(PKTDATA(osh, p) + offset, buf, n);
99 /* copy a buffer into a pkt buffer chain */
101 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
106 /* skip 'offset' bytes */
107 for (; p && offset; p = PKTNEXT(osh, p)) {
108 if (offset < (uint)PKTLEN(osh, p))
110 offset -= PKTLEN(osh, p);
117 for (; p && len; p = PKTNEXT(osh, p)) {
118 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
119 bcopy(buf, PKTDATA(osh, p) + offset, n);
131 /* return total length of buffer chain */
133 pkttotlen(osl_t *osh, void *p)
139 for (; p; p = PKTNEXT(osh, p)) {
140 len = PKTLEN(osh, p);
143 if (BCMLFRAG_ENAB()) {
144 if (PKTISFRAG(osh, p)) {
145 total += PKTFRAGTOTLEN(osh, p);
154 /* return the last buffer of chained pkt */
156 pktlast(osl_t *osh, void *p)
158 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
164 /* count segments of a chained packet */
166 pktsegcnt(osl_t *osh, void *p)
170 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
173 if (BCMLFRAG_ENAB()) {
174 if (PKTISFRAG(osh, p)) {
175 cnt += PKTFRAGTOTNUM(osh, p);
185 /* count segments of a chained packet */
187 pktsegcnt_war(osl_t *osh, void *p)
191 uint len, remain, align64;
193 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
195 len = PKTLEN(osh, p);
197 pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */
198 /* Check for page boundary straddle (2048B) */
199 if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
202 align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */
203 align64 = (64 - align64) & 0x3f;
204 len -= align64; /* bytes from aligned 64B to end */
205 /* if aligned to 128B, check for MOD 128 between 1 to 4B */
207 if (remain > 0 && remain <= 4)
208 cnt++; /* add extra seg */
216 pktdataoffset(osl_t *osh, void *p, uint offset)
218 uint total = pkttotlen(osh, p);
219 uint pkt_off = 0, len = 0;
220 uint8 *pdata = (uint8 *) PKTDATA(osh, p);
225 for (; p; p = PKTNEXT(osh, p)) {
226 pdata = (uint8 *) PKTDATA(osh, p);
227 pkt_off = offset - len;
228 len += PKTLEN(osh, p);
232 return (uint8*) (pdata+pkt_off);
236 /* given a offset in pdata, find the pkt seg hdr */
238 pktoffset(osl_t *osh, void *p, uint offset)
240 uint total = pkttotlen(osh, p);
246 for (; p; p = PKTNEXT(osh, p)) {
247 len += PKTLEN(osh, p);
254 #endif /* BCMDRIVER */
256 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
257 const unsigned char bcm_ctype[] = {
259 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
260 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
262 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
263 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
264 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
265 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
266 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
267 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
268 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
269 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
270 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
271 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
272 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
273 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
274 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
275 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
276 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
277 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
278 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
279 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
280 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
281 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
282 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
283 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
284 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
285 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
286 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
287 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
288 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
289 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
290 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
291 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
295 bcm_strtoul(const char *cp, char **endp, uint base)
297 ulong result, last_result = 0, value;
302 while (bcm_isspace(*cp))
307 else if (cp[0] == '-') {
314 if ((cp[1] == 'x') || (cp[1] == 'X')) {
323 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
329 while (bcm_isxdigit(*cp) &&
330 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
331 result = result*base + value;
332 /* Detected overflow */
333 if (result < last_result && !minus)
335 last_result = result;
340 result = (ulong)(-(long)result);
343 *endp = DISCARD_QUAL(cp, char);
349 bcm_atoi(const char *s)
351 return (int)bcm_strtoul(s, NULL, 10);
354 /* return pointer to location of substring 'needle' in 'haystack' */
356 bcmstrstr(const char *haystack, const char *needle)
361 if ((haystack == NULL) || (needle == NULL))
362 return DISCARD_QUAL(haystack, char);
364 nlen = (int)strlen(needle);
365 len = (int)strlen(haystack) - nlen + 1;
367 for (i = 0; i < len; i++)
368 if (memcmp(needle, &haystack[i], nlen) == 0)
369 return DISCARD_QUAL(&haystack[i], char);
374 bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len)
376 for (; s_len >= substr_len; s++, s_len--)
377 if (strncmp(s, substr, substr_len) == 0)
378 return DISCARD_QUAL(s, char);
384 bcmstrcat(char *dest, const char *src)
388 p = dest + strlen(dest);
390 while ((*p++ = *src++) != '\0')
397 bcmstrncat(char *dest, const char *src, uint size)
402 p = dest + strlen(dest);
405 while (p != endp && (*p++ = *src++) != '\0')
412 /****************************************************************************
413 * Function: bcmstrtok
416 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
417 * but allows strToken() to be used by different strings or callers at the same
418 * time. Each call modifies '*string' by substituting a NULL character for the
419 * first delimiter that is encountered, and updates 'string' to point to the char
420 * after the delimiter. Leading delimiters are skipped.
423 * string (mod) Ptr to string ptr, updated by token.
424 * delimiters (in) Set of delimiter characters.
425 * tokdelim (out) Character that delimits the returned token. (May
426 * be set to NULL if token delimiter is not required).
428 * Returns: Pointer to the next token found. NULL when no more tokens are found.
429 *****************************************************************************
432 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
435 unsigned long map[8];
439 if (tokdelim != NULL) {
440 /* Prime the token delimiter */
444 /* Clear control map */
445 for (count = 0; count < 8; count++) {
449 /* Set bits in delimiter table */
451 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
453 while (*delimiters++);
455 str = (unsigned char*)*string;
457 /* Find beginning of token (skip over leading delimiters). Note that
458 * there is no token iff this loop sets str to point to the terminal
459 * null (*str == '\0')
461 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
465 nextoken = (char*)str;
467 /* Find the end of the token. If it is not the end of the string,
470 for (; *str; str++) {
471 if (map[*str >> 5] & (1 << (*str & 31))) {
472 if (tokdelim != NULL) {
481 *string = (char*)str;
483 /* Determine if a token has been found. */
484 if (nextoken == (char *) str) {
493 #define xToLower(C) \
494 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
497 /****************************************************************************
498 * Function: bcmstricmp
500 * Purpose: Compare to strings case insensitively.
502 * Parameters: s1 (in) First string to compare.
503 * s2 (in) Second string to compare.
505 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
506 * t1 > t2, when ignoring case sensitivity.
507 *****************************************************************************
510 bcmstricmp(const char *s1, const char *s2)
517 if (dc < sc) return -1;
518 if (dc > sc) return 1;
523 if (*s1 && !*s2) return 1;
524 if (!*s1 && *s2) return -1;
529 /****************************************************************************
530 * Function: bcmstrnicmp
532 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
535 * Parameters: s1 (in) First string to compare.
536 * s2 (in) Second string to compare.
537 * cnt (in) Max characters to compare.
539 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
540 * t1 > t2, when ignoring case sensitivity.
541 *****************************************************************************
544 bcmstrnicmp(const char* s1, const char* s2, int cnt)
548 while (*s2 && *s1 && cnt) {
551 if (dc < sc) return -1;
552 if (dc > sc) return 1;
559 if (*s1 && !*s2) return 1;
560 if (!*s1 && *s2) return -1;
564 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
566 bcm_ether_atoe(const char *p, struct ether_addr *ea)
572 ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
582 bcm_atoipv4(const char *p, struct ipv4_addr *ip)
588 ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0);
589 if (*c++ != '.' || i == IPV4_ADDR_LEN)
593 return (i == IPV4_ADDR_LEN);
595 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
598 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
599 /* registry routine buffer preparation utility functions:
600 * parameter order is like strncpy, but returns count
601 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
604 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
612 /* wbuflen is in bytes */
613 wbuflen /= sizeof(ushort);
615 for (i = 0; i < wbuflen; ++i) {
618 *abuf++ = (char) *wbuf++;
625 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
628 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
630 static const char hex[] =
632 '0', '1', '2', '3', '4', '5', '6', '7',
633 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
635 const uint8 *octet = ea->octet;
639 for (i = 0; i < 6; i++, octet++) {
640 *p++ = hex[(*octet >> 4) & 0xf];
641 *p++ = hex[*octet & 0xf];
651 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
653 snprintf(buf, 16, "%d.%d.%d.%d",
654 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
659 bcm_ipv6_ntoa(void *ipv6, char *buf)
661 /* Implementing RFC 5952 Sections 4 + 5 */
662 /* Not thoroughly tested */
666 int i, i_max = -1, cnt = 0, cnt_max = 1;
668 memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
670 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
685 /* IPv4-translated: ::ffff:0:a.b.c.d */
686 ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
687 /* IPv4-mapped: ::ffff:a.b.c.d */
688 (cnt_max == 5 && a[5] == 0xffff)))
689 a4 = (uint8*) (a + 6);
691 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
692 if ((uint8*) (a + i) == a4) {
693 snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
695 } else if (i == i_max) {
703 p += snprintf(p, 8, "%x", ntoh16(a[i]));
716 for (i = 0; i < ms; i++) {
725 #if defined(DHD_DEBUG)
726 /* pretty hex print a pkt buffer chain */
728 prpkt(const char *msg, osl_t *osh, void *p0)
732 if (msg && (msg[0] != '\0'))
733 printf("%s:\n", msg);
735 for (p = p0; p; p = PKTNEXT(osh, p))
736 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
740 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
741 * Also updates the inplace vlan tag if requested.
742 * For debugging, it returns an indication of what it did.
745 pktsetprio(void *pkt, bool update_vtag)
747 struct ether_header *eh;
748 struct ethervlan_header *evh;
753 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
754 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
756 eh = (struct ether_header *) pktdata;
758 if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
760 int vlan_prio, dscp_prio = 0;
762 evh = (struct ethervlan_header *)eh;
764 vlan_tag = ntoh16(evh->vlan_tag);
765 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
767 if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
768 (evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
769 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
770 uint8 tos_tc = IP_TOS46(ip_body);
771 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
774 /* DSCP priority gets precedence over 802.1P (vlan tag) */
775 if (dscp_prio != 0) {
776 priority = dscp_prio;
779 priority = vlan_prio;
783 * If the DSCP priority is not the same as the VLAN priority,
784 * then overwrite the priority field in the vlan tag, with the
785 * DSCP priority value. This is required for Linux APs because
786 * the VLAN driver on Linux, overwrites the skb->priority field
787 * with the priority value in the vlan tag
789 if (update_vtag && (priority != vlan_prio)) {
790 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
791 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
792 evh->vlan_tag = hton16(vlan_tag);
795 } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
796 (eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
797 uint8 *ip_body = pktdata + sizeof(struct ether_header);
798 uint8 tos_tc = IP_TOS46(ip_body);
799 uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
802 priority = PRIO_8021D_VO;
807 priority = PRIO_8021D_CL;
815 priority = PRIO_8021D_EE;
818 #ifndef CUSTOM_DSCP_TO_PRIO_MAPPING
819 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
821 priority = (int)dscp2priomap[((tos_tc >> IPV4_TOS_DSCP_SHIFT)
822 & CUST_IPV4_TOS_PREC_MASK)];
830 ASSERT(priority >= 0 && priority <= MAXPRIO);
831 PKTSETPRIO(pkt, priority);
832 return (rc | priority);
835 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
838 pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
840 struct ether_header *eh;
841 struct ethervlan_header *evh;
845 /* minimum length is ether header and IP header */
846 if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
849 eh = (struct ether_header *) pktdata;
851 if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
852 ip_body = pktdata + sizeof(struct ether_header);
853 *dscp = IP_DSCP46(ip_body);
856 else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
857 evh = (struct ethervlan_header *)eh;
859 /* minimum length is ethervlan header and IP header */
860 if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
861 evh->ether_type == HTON16(ETHER_TYPE_IP)) {
862 ip_body = pktdata + sizeof(struct ethervlan_header);
863 *dscp = IP_DSCP46(ip_body);
871 /* The 0.5KB string table is not removed by compiler even though it's unused */
873 static char bcm_undeferrstr[32];
874 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
876 /* Convert the error codes into related error strings */
878 bcmerrorstr(int bcmerror)
880 /* check if someone added a bcmerror code but forgot to add errorstring */
881 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
883 if (bcmerror > 0 || bcmerror < BCME_LAST) {
884 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
885 return bcm_undeferrstr;
888 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
890 return bcmerrorstrtable[-bcmerror];
895 /* iovar table lookup */
896 /* could mandate sorted tables and do a binary search */
898 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
900 const bcm_iovar_t *vi;
901 const char *lookup_name;
903 /* skip any ':' delimited option prefixes */
904 lookup_name = strrchr(name, ':');
905 if (lookup_name != NULL)
910 ASSERT(table != NULL);
912 for (vi = table; vi->name; vi++) {
913 if (!strcmp(vi->name, lookup_name))
916 /* ran to end of table */
918 return NULL; /* var name not found */
922 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
926 /* length check on io buf */
935 /* all integers are int32 sized args at the ioctl interface */
936 if (len < (int)sizeof(int)) {
937 bcmerror = BCME_BUFTOOSHORT;
942 /* buffer must meet minimum length requirement */
943 if (len < vi->minlen) {
944 bcmerror = BCME_BUFTOOSHORT;
950 /* Cannot return nil... */
951 bcmerror = BCME_UNSUPPORTED;
953 /* Set is an action w/o parameters */
954 bcmerror = BCME_BUFTOOLONG;
959 /* unknown type for length check in iovar info */
961 bcmerror = BCME_UNSUPPORTED;
967 #endif /* BCMDRIVER */
971 bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst)
973 uint8 *new_dst = dst;
974 bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst;
976 /* dst buffer should always be valid */
979 /* data len must be within valid range */
980 ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE));
982 /* source data buffer pointer should be valid, unless datalen is 0
983 * meaning no data with this TLV
985 ASSERT((data != NULL) || (datalen == 0));
987 /* only do work if the inputs are valid
988 * - must have a dst to write to AND
989 * - datalen must be within range AND
990 * - the source data pointer must be non-NULL if datalen is non-zero
991 * (this last condition detects datalen > 0 with a NULL data pointer)
994 ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
995 ((data != NULL) || (datalen == 0))) {
997 /* write type, len fields */
998 dst_tlv->id = (uint8)type;
999 dst_tlv->len = (uint8)datalen;
1001 /* if data is present, copy to the output buffer and update
1002 * pointer to output buffer
1006 memcpy(dst_tlv->data, data, datalen);
1009 /* update the output destination poitner to point past
1012 new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
1019 bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen)
1021 uint8 *new_dst = dst;
1023 if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) {
1025 /* if len + tlv hdr len is more than destlen, don't do anything
1026 * just return the buffer untouched
1028 if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) {
1030 new_dst = bcm_write_tlv(type, data, datalen, dst);
1038 bcm_copy_tlv(const void *src, uint8 *dst)
1040 uint8 *new_dst = dst;
1041 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1047 totlen = BCM_TLV_HDR_SIZE + src_tlv->len;
1048 memcpy(dst, src_tlv, totlen);
1049 new_dst = dst + totlen;
1056 uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen)
1058 uint8 *new_dst = dst;
1059 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1063 if (bcm_valid_tlv(src_tlv, dst_maxlen)) {
1064 new_dst = bcm_copy_tlv(src, dst);
1072 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
1073 /*******************************************************************************
1076 * Computes a crc8 over the input data using the polynomial:
1078 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1080 * The caller provides the initial value (either CRC8_INIT_VALUE
1081 * or the previous returned value) to allow for processing of
1082 * discontiguous blocks of data. When generating the CRC the
1083 * caller is responsible for complementing the final return value
1084 * and inserting it into the byte stream. When checking, a final
1085 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1087 * Reference: Dallas Semiconductor Application Note 27
1088 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1089 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1090 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1092 * ****************************************************************************
1095 static const uint8 crc8_table[256] = {
1096 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1097 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1098 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1099 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1100 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1101 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1102 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1103 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1104 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1105 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1106 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1107 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1108 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1109 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1110 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1111 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1112 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1113 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1114 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1115 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1116 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1117 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1118 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1119 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1120 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1121 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1122 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1123 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1124 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1125 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1126 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1127 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1130 #define CRC_INNER_LOOP(n, c, x) \
1131 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1135 uint8 *pdata, /* pointer to array of data to process */
1136 uint nbytes, /* number of input data bytes to process */
1137 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1140 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1141 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1143 while (nbytes-- > 0)
1144 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1149 /*******************************************************************************
1152 * Computes a crc16 over the input data using the polynomial:
1154 * x^16 + x^12 +x^5 + 1
1156 * The caller provides the initial value (either CRC16_INIT_VALUE
1157 * or the previous returned value) to allow for processing of
1158 * discontiguous blocks of data. When generating the CRC the
1159 * caller is responsible for complementing the final return value
1160 * and inserting it into the byte stream. When checking, a final
1161 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1163 * Reference: Dallas Semiconductor Application Note 27
1164 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1165 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1166 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1168 * ****************************************************************************
1171 static const uint16 crc16_table[256] = {
1172 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1173 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1174 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1175 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1176 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1177 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1178 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1179 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1180 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1181 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1182 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1183 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1184 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1185 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1186 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1187 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1188 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1189 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1190 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1191 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1192 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1193 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1194 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1195 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1196 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1197 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1198 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1199 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1200 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1201 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1202 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1203 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1208 uint8 *pdata, /* pointer to array of data to process */
1209 uint nbytes, /* number of input data bytes to process */
1210 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1213 while (nbytes-- > 0)
1214 CRC_INNER_LOOP(16, crc, *pdata++);
1218 static const uint32 crc32_table[256] = {
1219 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1220 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1221 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1222 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1223 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1224 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1225 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1226 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1227 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1228 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1229 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1230 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1231 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1232 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1233 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1234 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1235 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1236 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1237 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1238 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1239 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1240 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1241 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1242 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1243 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1244 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1245 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1246 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1247 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1248 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1249 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1250 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1251 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1252 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1253 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1254 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1255 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1256 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1257 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1258 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1259 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1260 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1261 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1262 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1263 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1264 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1265 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1266 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1267 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1268 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1269 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1270 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1271 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1272 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1273 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1274 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1275 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1276 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1277 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1278 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1279 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1280 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1281 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1282 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1286 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
1287 * accumulating over multiple pieces.
1290 hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
1293 pend = pdata + nbytes;
1294 while (pdata < pend)
1295 CRC_INNER_LOOP(32, crc, *pdata++);
1301 #define CLEN 1499 /* CRC Length */
1302 #define CBUFSIZ (CLEN+4)
1303 #define CNBUFS 5 /* # of bufs */
1312 uint32 crc32tv[CNBUFS] =
1313 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1315 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1317 /* step through all possible alignments */
1318 for (l = 0; l <= 4; l++) {
1319 for (j = 0; j < CNBUFS; j++) {
1321 for (k = 0; k < len[j]; k++)
1322 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1325 for (j = 0; j < CNBUFS; j++) {
1326 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1327 ASSERT(crcr == crc32tv[j]);
1331 MFREE(buf, CBUFSIZ*CNBUFS);
1337 * Advance from the current 1-byte tag/1-byte length/variable-length value
1338 * triple, to the next, returning a pointer to the next.
1339 * If the current or next TLV is invalid (does not fit in given buffer length),
1341 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1342 * by the TLV parameter's length if it is valid.
1345 bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1349 /* validate current elt */
1350 if (!bcm_valid_tlv(elt, *buflen)) {
1354 /* advance to next elt */
1356 elt = (bcm_tlv_t*)(elt->data + len);
1357 *buflen -= (TLV_HDR_LEN + len);
1359 /* validate next elt */
1360 if (!bcm_valid_tlv(elt, *buflen)) {
1368 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1369 * triples, returning a pointer to the substring whose first element
1373 bcm_parse_tlvs(void *buf, int buflen, uint key)
1378 elt = (bcm_tlv_t*)buf;
1381 /* find tagged parameter */
1382 while (totlen >= TLV_HDR_LEN) {
1385 /* validate remaining totlen */
1386 if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
1391 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
1392 totlen -= (len + TLV_HDR_LEN);
1399 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1400 * triples, returning a pointer to the substring whose first element
1402 * return NULL if not found or length field < min_varlen
1405 bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen)
1407 bcm_tlv_t * ret = bcm_parse_tlvs(buf, buflen, key);
1408 if (ret == NULL || ret->len < min_bodylen) {
1415 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1416 * triples, returning a pointer to the substring whose first element
1417 * matches tag. Stop parsing when we see an element whose ID is greater
1418 * than the target key.
1421 bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1426 elt = (bcm_tlv_t*)buf;
1429 /* find tagged parameter */
1430 while (totlen >= TLV_HDR_LEN) {
1434 /* Punt if we start seeing IDs > than target key */
1439 /* validate remaining totlen */
1440 if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
1444 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
1445 totlen -= (len + TLV_HDR_LEN);
1449 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
1451 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1454 bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len)
1460 if (len < 2 || !buf)
1465 for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) {
1466 bit = bd->bitfield[i].bit;
1467 if ((flags & mask) == bit) {
1468 if (len > (int)strlen(name)) {
1469 slen = strlen(name);
1470 strncpy(buf, name, slen+1);
1479 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1484 int slen = 0, nlen = 0;
1488 if (len < 2 || !buf)
1493 for (i = 0; flags != 0; i++) {
1496 if (bit == 0 && flags != 0) {
1497 /* print any unnamed bits */
1498 snprintf(hexstr, 16, "0x%X", flags);
1500 flags = 0; /* exit loop */
1501 } else if ((flags & bit) == 0)
1504 nlen = strlen(name);
1506 /* count btwn flag space */
1509 /* need NULL char as well */
1512 /* copy NULL char but don't count it */
1513 strncpy(p, name, nlen + 1);
1515 /* copy btwn flag space and NULL char */
1517 p += snprintf(p, 2, " ");
1520 /* indicate the str was too short */
1523 p -= 2 - len; /* overwrite last char */
1524 p += snprintf(p, 2, ">");
1527 return (int)(p - buf);
1531 /* print bytes formatted as hex to a string. return the resulting string length */
1533 bcm_format_hex(char *str, const void *bytes, int len)
1537 const uint8 *src = (const uint8*)bytes;
1539 for (i = 0; i < len; i++) {
1540 p += snprintf(p, 3, "%02X", *src);
1543 return (int)(p - str);
1546 /* pretty hex print a contiguous buffer */
1548 prhex(const char *msg, uchar *buf, uint nbytes)
1551 int len = sizeof(line);
1555 if (msg && (msg[0] != '\0'))
1556 printf("%s:\n", msg);
1559 for (i = 0; i < nbytes; i++) {
1561 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
1566 nchar = snprintf(p, len, "%02x ", buf[i]);
1572 printf("%s\n", line); /* flush line */
1578 /* flush last partial line */
1580 printf("%s\n", line);
1583 static const char *crypto_algo_names[] = {
1615 bcm_crypto_algo_name(uint algo)
1617 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
1622 bcm_chipname(uint chipid, char *buf, uint len)
1626 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
1627 snprintf(buf, len, fmt, chipid);
1631 /* Produce a human-readable string for boardrev */
1633 bcm_brev_str(uint32 brev, char *buf)
1636 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1638 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1643 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1645 /* dump large strings to console */
1652 len = (uint)strlen(buf);
1654 max_len = BUFSIZE_TODUMP_ATONCE;
1656 while (len > max_len) {
1658 buf[max_len] = '\0';
1665 /* print the remaining string */
1666 printf("%s\n", buf);
1670 /* routine to dump fields in a fileddesc structure */
1672 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
1673 char *buf, uint32 bufsize)
1677 struct fielddesc *cur_ptr;
1680 cur_ptr = fielddesc_array;
1682 while (bufsize > 1) {
1683 if (cur_ptr->nameandfmt == NULL)
1685 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1686 read_rtn(arg0, arg1, cur_ptr->offset));
1687 /* check for snprintf overflow or error */
1688 if (len < 0 || (uint32)len >= bufsize)
1699 bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1703 len = (uint)strlen(name) + 1;
1705 if ((len + datalen) > buflen)
1708 strncpy(buf, name, buflen);
1710 /* append data onto the end of the name string */
1711 memcpy(&buf[len], data, datalen);
1717 /* Quarter dBm units to mW
1718 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1719 * Table is offset so the last entry is largest mW value that fits in
1723 #define QDBM_OFFSET 153 /* Offset for first entry */
1724 #define QDBM_TABLE_LEN 40 /* Table size */
1726 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1727 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1729 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1731 /* Largest mW value that will round down to the last table entry,
1732 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1733 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1735 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1737 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1738 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1739 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1740 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1741 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1742 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1743 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1747 bcm_qdbm_to_mw(uint8 qdbm)
1750 int idx = qdbm - QDBM_OFFSET;
1752 if (idx >= QDBM_TABLE_LEN) {
1753 /* clamp to max uint16 mW value */
1757 /* scale the qdBm index up to the range of the table 0-40
1758 * where an offset of 40 qdBm equals a factor of 10 mW.
1765 /* return the mW value scaled down to the correct factor of 10,
1766 * adding in factor/2 to get proper rounding.
1768 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
1772 bcm_mw_to_qdbm(uint16 mw)
1779 /* handle boundary case */
1783 offset = QDBM_OFFSET;
1785 /* move mw into the range of the table */
1786 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1791 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
1792 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
1793 nqdBm_to_mW_map[qdbm])/2;
1794 if (mw_uint < boundary) break;
1797 qdbm += (uint8)offset;
1804 bcm_bitcount(uint8 *bitmap, uint length)
1806 uint bitcount = 0, i;
1808 for (i = 0; i < length; i++) {
1820 /* Initialization of bcmstrbuf structure */
1822 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1824 b->origsize = b->size = size;
1825 b->origbuf = b->buf = buf;
1828 /* Buffer sprintf wrapper to guard against buffer overflow */
1830 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1837 r = vsnprintf(b->buf, b->size, fmt, ap);
1839 /* Non Ansi C99 compliant returns -1,
1840 * Ansi compliant return r >= b->size,
1841 * bcmstdlib returns 0, handle all
1843 /* r == 0 is also the case when strlen(fmt) is zero.
1844 * typically the case when "" is passed as argument.
1846 if ((r == -1) || (r >= (int)b->size)) {
1859 bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len)
1863 if (msg != NULL && msg[0] != '\0')
1864 bcm_bprintf(b, "%s", msg);
1865 for (i = 0; i < len; i ++)
1866 bcm_bprintf(b, "%02X", buf[i]);
1868 bcm_bprintf(b, "\n");
1872 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1876 for (i = 0; i < num_bytes; i++) {
1878 if (num[i] >= amount)
1885 bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
1889 for (i = nbytes - 1; i >= 0; i--) {
1890 if (arg1[i] != arg2[i])
1891 return (arg1[i] - arg2[i]);
1897 bcm_print_bytes(const char *name, const uchar *data, int len)
1902 printf("%s: %d \n", name ? name : "", len);
1903 for (i = 0; i < len; i++) {
1904 printf("%02x ", *data++);
1906 if (per_line == 16) {
1914 /* Look for vendor-specific IE with specified OUI and optional type */
1916 bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len)
1921 ie = (bcm_tlv_t*)tlvs;
1923 /* make sure we are looking at a valid IE */
1924 if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
1928 /* Walk through the IEs looking for an OUI match */
1931 if ((ie->id == DOT11_MNG_PROPR_ID) &&
1932 (ie_len >= (DOT11_OUI_LEN + type_len)) &&
1933 !bcmp(ie->data, voui, DOT11_OUI_LEN))
1935 /* compare optional type */
1936 if (type_len == 0 ||
1937 !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
1938 return (ie); /* a match */
1941 } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
1946 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1947 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1948 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1951 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
1955 char *endp = buf + SSID_FMT_BUF_LEN;
1957 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
1959 for (i = 0; i < ssid_len; i++) {
1964 } else if (bcm_isprint((uchar)c)) {
1967 p += snprintf(p, (endp - p), "\\x%02X", c);
1973 return (int)(p - buf);
1977 #endif /* BCMDRIVER */
1980 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
1981 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
1982 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
1983 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
1987 process_nvram_vars(char *varbuf, unsigned int len)
1992 unsigned int buf_len, n;
1993 unsigned int pad = 0;
1997 findNewline = FALSE;
2000 // terence 20130914: print out NVRAM version
2001 if (varbuf[0] == '#') {
2002 printf("NVRAM version: ");
2003 for (n=1; n<len; n++) {
2004 if (varbuf[n] == '\n')
2006 printk("%c", varbuf[n]);
2011 for (n = 0; n < len; n++) {
2012 if (varbuf[n] == '\r')
2014 if (findNewline && varbuf[n] != '\n')
2016 findNewline = FALSE;
2017 if (varbuf[n] == '#') {
2021 if (varbuf[n] == '\n') {
2031 buf_len = (unsigned int)(dp - varbuf);
2033 pad = 4 - buf_len % 4;
2034 if (pad && (buf_len + pad <= len)) {
2039 while (dp < varbuf + n)
2045 /* calculate a * b + c */
2047 bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
2049 #define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
2051 uint32 a1, a0, b1, b0, t, cc = 0;
2061 t = (a1 * b0) << 16;
2067 t = (a0 * b1) << 16;
2078 r0 |= (cc % 2) ? 0x80000000 : 0;
2079 r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2);
2085 /* calculate a / b */
2087 bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
2089 uint32 a1 = a_high, a0 = a_low, r0 = 0;
2095 r0 += (0xffffffff / b) * a1;
2096 bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
2103 #ifndef setbit /* As in the header file */
2104 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
2105 /* Set bit in byte array. */
2107 setbit(void *array, uint bit)
2109 ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
2112 /* Clear bit in byte array. */
2114 clrbit(void *array, uint bit)
2116 ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
2119 /* Test if bit is set in byte array. */
2121 isset(const void *array, uint bit)
2123 return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY)));
2126 /* Test if bit is clear in byte array. */
2128 isclr(const void *array, uint bit)
2130 return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0);
2132 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
2136 set_bitrange(void *array, uint start, uint end, uint maxbit)
2138 uint startbyte = start/NBBY;
2139 uint endbyte = end/NBBY;
2140 uint i, startbytelastbit, endbytestartbit;
2143 if (endbyte - startbyte > 1)
2145 startbytelastbit = (startbyte+1)*NBBY - 1;
2146 endbytestartbit = endbyte*NBBY;
2147 for (i = startbyte+1; i < endbyte; i++)
2148 ((uint8 *)array)[i] = 0xFF;
2149 for (i = start; i <= startbytelastbit; i++)
2151 for (i = endbytestartbit; i <= end; i++)
2154 for (i = start; i <= end; i++)
2159 set_bitrange(array, start, maxbit, maxbit);
2160 set_bitrange(array, 0, end, maxbit);
2165 bcm_bitprint32(const uint32 u32)
2168 for (i = NBITS(uint32) - 1; i >= 0; i--) {
2169 isbitset(u32, i) ? printf("1") : printf("0");
2170 if ((i % NBBY) == 0) printf(" ");
2175 /* calculate checksum for ip header, tcp / udp header / data */
2177 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
2180 sum += (buf[0] << 8) | buf[1];
2190 sum = (sum & 0xffff) + (sum >> 16);
2193 return ((uint16)~sum);
2198 * Hierarchical Multiword bitmap based small id allocator.
2200 * Multilevel hierarchy bitmap. (maximum 2 levels)
2201 * First hierarchy uses a multiword bitmap to identify 32bit words in the
2202 * second hierarchy that have at least a single bit set. Each bit in a word of
2203 * the second hierarchy represents a unique ID that may be allocated.
2205 * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
2206 * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
2207 * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
2208 * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
2209 * non-zero bitmap word carrying at least one free ID.
2210 * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
2211 * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
2214 * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
2215 * bits are computed each time on allocation and deallocation, requiring 4
2216 * array indexed access and 3 arithmetic operations. When not defined, a runtime
2217 * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
2218 * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
2219 * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
2220 * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
2222 * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
2223 * size is fixed. No intention to support larger than 4K indice allocation. ID
2224 * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
2225 * with savings in not having to use an indirect access, had it been dynamically
2228 #define BCM_MWBMAP_ITEMS_MAX (4 * 1024) /* May increase to 16K */
2230 #define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
2231 #define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
2232 #define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
2233 #define BCM_MWBMAP_SHIFT_OP (5)
2234 #define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
2235 #define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
2236 #define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
2238 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
2239 #define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
2240 #define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
2242 #if defined(BCM_MWBMAP_DEBUG)
2243 #define BCM_MWBMAP_AUDIT(mwb) \
2245 ASSERT((mwb != NULL) && \
2246 (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
2247 bcm_mwbmap_audit(mwb); \
2249 #define MWBMAP_ASSERT(exp) ASSERT(exp)
2250 #define MWBMAP_DBG(x) printf x
2251 #else /* !BCM_MWBMAP_DEBUG */
2252 #define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
2253 #define MWBMAP_ASSERT(exp) do {} while (0)
2254 #define MWBMAP_DBG(x)
2255 #endif /* !BCM_MWBMAP_DEBUG */
2258 typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
2259 uint16 wmaps; /* Total number of words in free wd bitmap */
2260 uint16 imaps; /* Total number of words in free id bitmap */
2261 int16 ifree; /* Count of free indices. Used only in audits */
2262 uint16 total; /* Total indices managed by multiword bitmap */
2264 void * magic; /* Audit handle parameter from user */
2266 uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */
2267 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2268 int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */
2269 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2271 uint32 id_bitmap[0]; /* Second level bitmap */
2274 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
2276 bcm_mwbmap_init(osl_t *osh, uint32 items_max)
2278 struct bcm_mwbmap * mwbmap_p;
2279 uint32 wordix, size, words, extra;
2281 /* Implementation Constraint: Uses 32bit word bitmap */
2282 MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
2283 MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
2284 MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
2285 MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
2287 ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
2289 /* Determine the number of words needed in the multiword bitmap */
2290 extra = BCM_MWBMAP_MODOP(items_max);
2291 words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
2293 /* Allocate runtime state of multiword bitmap */
2294 /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
2295 size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
2296 mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
2297 if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
2301 memset(mwbmap_p, 0, size);
2303 /* Initialize runtime multiword bitmap state */
2304 mwbmap_p->imaps = (uint16)words;
2305 mwbmap_p->ifree = (int16)items_max;
2306 mwbmap_p->total = (uint16)items_max;
2308 /* Setup magic, for use in audit of handle */
2309 mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
2311 /* Setup the second level bitmap of free indices */
2312 /* Mark all indices as available */
2313 for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
2314 mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
2315 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2316 mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
2317 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2320 /* Ensure that extra indices are tagged as un-available */
2321 if (extra) { /* fixup the free ids in last bitmap and wd_count */
2322 uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
2323 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2324 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2325 mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
2326 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2329 /* Setup the first level bitmap hierarchy */
2330 extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
2331 words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
2333 mwbmap_p->wmaps = (uint16)words;
2335 for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
2336 mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
2338 uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
2339 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2345 return BCM_MWBMAP_INVALID_HDL;
2348 /* Release resources used by multiword bitmap based small index allocator. */
2350 bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
2352 bcm_mwbmap_t * mwbmap_p;
2354 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2355 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2357 MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
2358 + (sizeof(uint32) * mwbmap_p->imaps));
2362 /* Allocate a unique small index using a multiword bitmap index allocator. */
2364 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
2366 bcm_mwbmap_t * mwbmap_p;
2367 uint32 wordix, bitmap;
2369 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2370 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2372 /* Start with the first hierarchy */
2373 for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
2375 bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
2379 uint32 count, bitix, *bitmap_p;
2381 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2383 /* clear all except trailing 1 */
2384 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
2385 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
2386 bcm_count_leading_zeros(bitmap));
2387 bitix = (BCM_MWBMAP_BITS_WORD - 1)
2388 - bcm_count_leading_zeros(bitmap); /* use asm clz */
2389 wordix = BCM_MWBMAP_MULOP(wordix) + bitix;
2391 /* Clear bit if wd count is 0, without conditional branch */
2392 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2393 count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
2394 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2395 mwbmap_p->wd_count[wordix]--;
2396 count = mwbmap_p->wd_count[wordix];
2397 MWBMAP_ASSERT(count ==
2398 (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
2399 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2400 MWBMAP_ASSERT(count >= 0);
2402 /* clear wd_bitmap bit if id_map count is 0 */
2403 bitmap = (count == 0) << bitix;
2406 "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
2407 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
2409 *bitmap_p ^= bitmap;
2411 /* Use bitix in the second hierarchy */
2412 bitmap_p = &mwbmap_p->id_bitmap[wordix];
2414 bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
2415 MWBMAP_ASSERT(bitmap != 0U);
2417 /* clear all except trailing 1 */
2418 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
2419 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
2420 bcm_count_leading_zeros(bitmap));
2421 bitix = BCM_MWBMAP_MULOP(wordix)
2422 + (BCM_MWBMAP_BITS_WORD - 1)
2423 - bcm_count_leading_zeros(bitmap); /* use asm clz */
2425 mwbmap_p->ifree--; /* decrement system wide free count */
2426 MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
2429 "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
2430 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
2433 *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
2439 ASSERT(mwbmap_p->ifree == 0);
2441 return BCM_MWBMAP_INVALID_IDX;
2444 /* Force an index at a specified position to be in use */
2446 bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
2448 bcm_mwbmap_t * mwbmap_p;
2449 uint32 count, wordix, bitmap, *bitmap_p;
2451 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2452 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2454 ASSERT(bitix < mwbmap_p->total);
2456 /* Start with second hierarchy */
2457 wordix = BCM_MWBMAP_DIVOP(bitix);
2458 bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
2459 bitmap_p = &mwbmap_p->id_bitmap[wordix];
2461 ASSERT((*bitmap_p & bitmap) == bitmap);
2463 mwbmap_p->ifree--; /* update free count */
2464 ASSERT(mwbmap_p->ifree >= 0);
2466 MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
2467 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
2470 *bitmap_p ^= bitmap; /* mark as in use */
2472 /* Update first hierarchy */
2475 wordix = BCM_MWBMAP_DIVOP(bitix);
2476 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2478 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2479 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
2480 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2481 mwbmap_p->wd_count[bitix]--;
2482 count = mwbmap_p->wd_count[bitix];
2483 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
2484 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2485 MWBMAP_ASSERT(count >= 0);
2487 bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix);
2489 MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
2490 BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
2491 (*bitmap_p) ^ bitmap, count));
2493 *bitmap_p ^= bitmap; /* mark as in use */
2498 /* Free a previously allocated index back into the multiword bitmap allocator */
2500 bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
2502 bcm_mwbmap_t * mwbmap_p;
2503 uint32 wordix, bitmap, *bitmap_p;
2505 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2506 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2508 ASSERT(bitix < mwbmap_p->total);
2510 /* Start with second level hierarchy */
2511 wordix = BCM_MWBMAP_DIVOP(bitix);
2512 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
2513 bitmap_p = &mwbmap_p->id_bitmap[wordix];
2515 ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */
2517 mwbmap_p->ifree++; /* update free count */
2518 ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
2520 MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
2521 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
2524 *bitmap_p |= bitmap; /* mark as available */
2526 /* Now update first level hierarchy */
2530 wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
2531 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
2532 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2534 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2535 mwbmap_p->wd_count[bitix]++;
2538 #if defined(BCM_MWBMAP_DEBUG)
2541 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2542 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
2543 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2544 count = mwbmap_p->wd_count[bitix];
2545 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
2546 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2548 MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
2550 MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
2551 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
2553 #endif /* BCM_MWBMAP_DEBUG */
2555 *bitmap_p |= bitmap;
2560 /* Fetch the toal number of free indices in the multiword bitmap allocator */
2562 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
2564 bcm_mwbmap_t * mwbmap_p;
2566 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2567 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2569 ASSERT(mwbmap_p->ifree >= 0);
2571 return mwbmap_p->ifree;
2574 /* Determine whether an index is inuse or free */
2576 bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
2578 bcm_mwbmap_t * mwbmap_p;
2579 uint32 wordix, bitmap;
2581 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2582 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2584 ASSERT(bitix < mwbmap_p->total);
2586 wordix = BCM_MWBMAP_DIVOP(bitix);
2587 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
2589 return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
2592 /* Debug dump a multiword bitmap allocator */
2594 bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
2597 bcm_mwbmap_t * mwbmap_p;
2599 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2600 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2602 printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p,
2603 mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
2604 for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
2605 printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
2606 bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
2609 for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
2610 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2611 count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
2612 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2613 count = mwbmap_p->wd_count[ix];
2614 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
2615 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2616 printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
2617 bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
2624 /* Audit a hierarchical multiword bitmap */
2626 bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
2628 bcm_mwbmap_t * mwbmap_p;
2629 uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
2631 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2633 for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
2635 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2637 for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
2638 if ((*bitmap_p) & (1 << bitix)) {
2639 idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
2640 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2641 count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
2642 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2643 count = mwbmap_p->wd_count[idmap_ix];
2644 ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
2645 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2646 ASSERT(count != 0U);
2652 ASSERT((int)free_cnt == mwbmap_p->ifree);
2654 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
2656 /* Simple 16bit Id allocator using a stack implementation. */
2657 typedef struct id16_map {
2658 uint16 total; /* total number of ids managed by allocator */
2659 uint16 start; /* start value of 16bit ids to be managed */
2660 uint32 failures; /* count of failures */
2661 void *dbg; /* debug placeholder */
2662 int stack_idx; /* index into stack of available ids */
2663 uint16 stack[0]; /* stack of 16 bit ids */
2666 #define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \
2667 (sizeof(uint16) * (items)))
2669 #if defined(BCM_DBG)
2671 /* Uncomment BCM_DBG_ID16 to debug double free */
2672 /* #define BCM_DBG_ID16 */
2674 typedef struct id16_map_dbg {
2678 #define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \
2679 (sizeof(bool) * (items)))
2680 #define ID16_MAP_MSG(x) print x
2682 #define ID16_MAP_MSG(x)
2683 #endif /* BCM_DBG */
2685 void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
2686 id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
2689 id16_map_t * id16_map;
2691 ASSERT(total_ids > 0);
2692 ASSERT((start_val16 + total_ids) < ID16_INVALID);
2694 id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
2695 if (id16_map == NULL) {
2699 id16_map->total = total_ids;
2700 id16_map->start = start_val16;
2701 id16_map->failures = 0;
2702 id16_map->dbg = NULL;
2704 /* Populate stack with 16bit id values, commencing with start_val16 */
2705 id16_map->stack_idx = 0;
2706 val16 = start_val16;
2708 for (idx = 0; idx < total_ids; idx++, val16++) {
2709 id16_map->stack_idx = idx;
2710 id16_map->stack[id16_map->stack_idx] = val16;
2713 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2714 id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
2716 if (id16_map->dbg) {
2717 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
2719 id16_map_dbg->total = total_ids;
2720 for (idx = 0; idx < total_ids; idx++) {
2721 id16_map_dbg->avail[idx] = TRUE;
2724 #endif /* BCM_DBG && BCM_DBG_ID16 */
2726 return (void *)id16_map;
2729 void * /* Destruct an id16 allocator instance */
2730 id16_map_fini(osl_t *osh, void * id16_map_hndl)
2733 id16_map_t * id16_map;
2735 if (id16_map_hndl == NULL)
2738 id16_map = (id16_map_t *)id16_map_hndl;
2740 total_ids = id16_map->total;
2741 ASSERT(total_ids > 0);
2743 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2744 if (id16_map->dbg) {
2745 MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
2746 id16_map->dbg = NULL;
2748 #endif /* BCM_DBG && BCM_DBG_ID16 */
2750 id16_map->total = 0;
2751 MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
2757 id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
2760 id16_map_t * id16_map;
2762 ASSERT(total_ids > 0);
2763 ASSERT((start_val16 + total_ids) < ID16_INVALID);
2765 id16_map = (id16_map_t *)id16_map_hndl;
2766 if (id16_map == NULL) {
2770 id16_map->total = total_ids;
2771 id16_map->start = start_val16;
2772 id16_map->failures = 0;
2774 /* Populate stack with 16bit id values, commencing with start_val16 */
2775 id16_map->stack_idx = 0;
2776 val16 = start_val16;
2778 for (idx = 0; idx < total_ids; idx++, val16++) {
2779 id16_map->stack_idx = idx;
2780 id16_map->stack[id16_map->stack_idx] = val16;
2783 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2784 if (id16_map->dbg) {
2785 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
2787 id16_map_dbg->total = total_ids;
2788 for (idx = 0; idx < total_ids; idx++) {
2789 id16_map_dbg->avail[idx] = TRUE;
2792 #endif /* BCM_DBG && BCM_DBG_ID16 */
2795 uint16 BCMFASTPATH /* Allocate a unique 16bit id */
2796 id16_map_alloc(void * id16_map_hndl)
2799 id16_map_t * id16_map;
2801 ASSERT(id16_map_hndl != NULL);
2803 id16_map = (id16_map_t *)id16_map_hndl;
2805 ASSERT(id16_map->total > 0);
2807 if (id16_map->stack_idx < 0) {
2808 id16_map->failures++;
2809 return ID16_INVALID;
2812 val16 = id16_map->stack[id16_map->stack_idx];
2813 id16_map->stack_idx--;
2815 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2817 ASSERT(val16 < (id16_map->start + id16_map->total));
2819 if (id16_map->dbg) { /* Validate val16 */
2820 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
2822 ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
2823 id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
2825 #endif /* BCM_DBG && BCM_DBG_ID16 */
2831 void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
2832 id16_map_free(void * id16_map_hndl, uint16 val16)
2834 id16_map_t * id16_map;
2836 ASSERT(id16_map_hndl != NULL);
2838 id16_map = (id16_map_t *)id16_map_hndl;
2840 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2842 ASSERT(val16 < (id16_map->start + id16_map->total));
2844 if (id16_map->dbg) { /* Validate val16 */
2845 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
2847 ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
2848 id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
2850 #endif /* BCM_DBG && BCM_DBG_ID16 */
2852 id16_map->stack_idx++;
2853 id16_map->stack[id16_map->stack_idx] = val16;
2856 uint32 /* Returns number of failures to allocate an unique id16 */
2857 id16_map_failures(void * id16_map_hndl)
2859 ASSERT(id16_map_hndl != NULL);
2860 return ((id16_map_t *)id16_map_hndl)->failures;
2864 id16_map_audit(void * id16_map_hndl)
2868 id16_map_t * id16_map;
2870 ASSERT(id16_map_hndl != NULL);
2872 id16_map = (id16_map_t *)id16_map_hndl;
2874 ASSERT((id16_map->stack_idx > 0) && (id16_map->stack_idx < id16_map->total));
2875 for (idx = 0; idx <= id16_map->stack_idx; idx++) {
2876 ASSERT(id16_map->stack[idx] >= id16_map->start);
2877 ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
2879 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2880 if (id16_map->dbg) {
2881 uint16 val16 = id16_map->stack[idx];
2882 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
2884 ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
2885 id16_map_hndl, idx, val16));
2888 #endif /* BCM_DBG && BCM_DBG_ID16 */
2891 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2892 if (id16_map->dbg) {
2893 uint16 avail = 0; /* Audit available ids counts */
2894 for (idx = 0; idx < id16_map_dbg->total; idx++) {
2895 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
2898 if (avail && (avail != (id16_map->stack_idx + 1))) {
2900 ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
2901 id16_map_hndl, avail, id16_map->stack_idx));
2904 #endif /* BCM_DBG && BCM_DBG_ID16 */
2908 /* END: Simple id16 allocator */
2911 #endif /* BCMDRIVER */
2913 /* calculate a >> b; and returns only lower 32 bits */
2915 bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
2917 uint32 a1 = a_high, a0 = a_low, r0 = 0;
2927 a1 = a1 & ((1 << b) - 1);
2928 a1 = a1 << (32 - b);
2933 r0 = a1 >> (b - 32);
2940 /* calculate a + b where a is a 64 bit number and b is a 32 bit number */
2942 bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset)
2944 uint32 r1_lo = *r_lo;
2950 /* calculate a - b where a is a 64 bit number and b is a 32 bit number */
2952 bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset)
2954 uint32 r1_lo = *r_lo;
2960 #ifdef DEBUG_COUNTER
2961 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
2962 void counter_printlog(counter_tbl_t *ctr_tbl)
2966 if (!ctr_tbl->enabled)
2969 now = OSL_SYSUPTIME();
2971 if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) {
2973 printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print);
2975 for (i = 0; i < ctr_tbl->needed_cnt; i++) {
2976 printf(" %u", ctr_tbl->cnt[i]);
2980 ctr_tbl->prev_log_print = now;
2981 bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint));
2985 /* OSL_SYSUPTIME is not supported so no way to get time */
2986 #define counter_printlog(a) do {} while (0)
2987 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
2988 #endif /* DEBUG_COUNTER */
2992 dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
2995 mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
2997 MFREE(osh, pool, mem_size);
3000 dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size)
3003 dll_pool_t * dll_pool_p;
3006 ASSERT(elem_size > sizeof(dll_t));
3008 mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
3010 if ((dll_pool_p = (dll_pool_t *)MALLOC(osh, mem_size)) == NULL) {
3011 printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
3012 elems_max, elem_size);
3017 bzero(dll_pool_p, mem_size);
3019 dll_init(&dll_pool_p->free_list);
3020 dll_pool_p->elems_max = elems_max;
3021 dll_pool_p->elem_size = elem_size;
3023 elem_p = dll_pool_p->elements;
3024 for (i = 0; i < elems_max; i++) {
3025 dll_append(&dll_pool_p->free_list, elem_p);
3026 elem_p = (dll_t *)((uintptr)elem_p + elem_size);
3029 dll_pool_p->free_count = elems_max;
3036 dll_pool_alloc(dll_pool_t * dll_pool_p)
3040 if (dll_pool_p->free_count == 0) {
3041 ASSERT(dll_empty(&dll_pool_p->free_list));
3045 elem_p = dll_head_p(&dll_pool_p->free_list);
3047 dll_pool_p->free_count -= 1;
3049 return (void *)elem_p;
3053 dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p)
3055 dll_t * node_p = (dll_t *)elem_p;
3056 dll_prepend(&dll_pool_p->free_list, node_p);
3057 dll_pool_p->free_count += 1;
3062 dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
3064 dll_t * node_p = (dll_t *)elem_p;
3065 dll_append(&dll_pool_p->free_list, node_p);
3066 dll_pool_p->free_count += 1;
3069 #endif /* BCMDRIVER */