2 * Driver O/S-independent utility routines
4 * Copyright (C) 1999-2019, Broadcom.
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.
25 * <<Broadcom-WL-IPTag/Open:>>
27 * $Id: bcmutils.c 813756 2019-04-08 05:18:14Z $
38 #else /* !BCMDRIVER */
45 #if defined(BCMEXTSUP)
53 #endif /* !BCMDRIVER */
60 #endif /* WL_UNITTEST */
62 #include <bcmendian.h>
75 /* return total length of buffer chain */
77 pkttotlen(osl_t
*osh
, void *p
)
83 for (; p
; p
= PKTNEXT(osh
, p
)) {
87 if (BCMLFRAG_ENAB()) {
88 if (PKTISFRAG(osh
, p
)) {
89 total
+= PKTFRAGTOTLEN(osh
, p
);
98 /* return the last buffer of chained pkt */
100 pktlast(osl_t
*osh
, void *p
)
102 for (; PKTNEXT(osh
, p
); p
= PKTNEXT(osh
, p
))
108 /* count segments of a chained packet */
110 pktsegcnt(osl_t
*osh
, void *p
)
114 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
)) {
117 if (BCMLFRAG_ENAB()) {
118 if (PKTISFRAG(osh
, p
)) {
119 cnt
+= PKTFRAGTOTNUM(osh
, p
);
128 /* copy a pkt buffer chain into a buffer */
130 pktcopy(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
135 len
= 4096; /* "infinite" */
137 /* skip 'offset' bytes */
138 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
139 if (offset
< (uint
)PKTLEN(osh
, p
))
141 offset
-= PKTLEN(osh
, p
);
148 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
149 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
150 bcopy(PKTDATA(osh
, p
) + offset
, buf
, n
);
160 /* copy a buffer into a pkt buffer chain */
162 pktfrombuf(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
166 /* skip 'offset' bytes */
167 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
168 if (offset
< (uint
)PKTLEN(osh
, p
))
170 offset
-= PKTLEN(osh
, p
);
177 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
178 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
179 bcopy(buf
, PKTDATA(osh
, p
) + offset
, n
);
190 pktdataoffset(osl_t
*osh
, void *p
, uint offset
)
192 uint total
= pkttotlen(osh
, p
);
193 uint pkt_off
= 0, len
= 0;
194 uint8
*pdata
= (uint8
*) PKTDATA(osh
, p
);
199 for (; p
; p
= PKTNEXT(osh
, p
)) {
200 pdata
= (uint8
*) PKTDATA(osh
, p
);
201 pkt_off
= offset
- len
;
202 len
+= PKTLEN(osh
, p
);
206 return (uint8
*) (pdata
+pkt_off
);
209 /* given a offset in pdata, find the pkt seg hdr */
211 pktoffset(osl_t
*osh
, void *p
, uint offset
)
213 uint total
= pkttotlen(osh
, p
);
219 for (; p
; p
= PKTNEXT(osh
, p
)) {
220 len
+= PKTLEN(osh
, p
);
232 for (i
= 0; i
< ms
; i
++) {
237 #if defined(DHD_DEBUG)
238 /* pretty hex print a pkt buffer chain */
240 prpkt(const char *msg
, osl_t
*osh
, void *p0
)
244 if (msg
&& (msg
[0] != '\0'))
245 printf("%s:\n", msg
);
247 for (p
= p0
; p
; p
= PKTNEXT(osh
, p
))
248 prhex(NULL
, PKTDATA(osh
, p
), PKTLEN(osh
, p
));
252 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
253 * Also updates the inplace vlan tag if requested.
254 * For debugging, it returns an indication of what it did.
257 pktsetprio(void *pkt
, bool update_vtag
)
259 struct ether_header
*eh
;
260 struct ethervlan_header
*evh
;
265 pktdata
= (uint8
*)PKTDATA(OSH_NULL
, pkt
);
266 ASSERT(ISALIGNED((uintptr
)pktdata
, sizeof(uint16
)));
268 eh
= (struct ether_header
*) pktdata
;
270 if (eh
->ether_type
== hton16(ETHER_TYPE_8021Q
)) {
272 int vlan_prio
, dscp_prio
= 0;
274 evh
= (struct ethervlan_header
*)eh
;
276 vlan_tag
= ntoh16(evh
->vlan_tag
);
277 vlan_prio
= (int) (vlan_tag
>> VLAN_PRI_SHIFT
) & VLAN_PRI_MASK
;
279 if ((evh
->ether_type
== hton16(ETHER_TYPE_IP
)) ||
280 (evh
->ether_type
== hton16(ETHER_TYPE_IPV6
))) {
281 uint8
*ip_body
= pktdata
+ sizeof(struct ethervlan_header
);
282 uint8 tos_tc
= IP_TOS46(ip_body
);
283 dscp_prio
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
286 /* DSCP priority gets precedence over 802.1P (vlan tag) */
287 if (dscp_prio
!= 0) {
288 priority
= dscp_prio
;
291 priority
= vlan_prio
;
295 * If the DSCP priority is not the same as the VLAN priority,
296 * then overwrite the priority field in the vlan tag, with the
297 * DSCP priority value. This is required for Linux APs because
298 * the VLAN driver on Linux, overwrites the skb->priority field
299 * with the priority value in the vlan tag
301 if (update_vtag
&& (priority
!= vlan_prio
)) {
302 vlan_tag
&= ~(VLAN_PRI_MASK
<< VLAN_PRI_SHIFT
);
303 vlan_tag
|= (uint16
)priority
<< VLAN_PRI_SHIFT
;
304 evh
->vlan_tag
= hton16(vlan_tag
);
307 #if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING)
308 } else if (eh
->ether_type
== hton16(ETHER_TYPE_802_1X
)) {
309 priority
= PRIO_8021D_NC
;
311 #endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */
312 } else if ((eh
->ether_type
== hton16(ETHER_TYPE_IP
)) ||
313 (eh
->ether_type
== hton16(ETHER_TYPE_IPV6
))) {
314 uint8
*ip_body
= pktdata
+ sizeof(struct ether_header
);
315 uint8 tos_tc
= IP_TOS46(ip_body
);
316 uint8 dscp
= tos_tc
>> IPV4_TOS_DSCP_SHIFT
;
320 priority
= PRIO_8021D_VO
;
326 priority
= PRIO_8021D_CL
;
331 priority
= PRIO_8021D_EE
;
337 priority
= PRIO_8021D_BE
;
340 priority
= PRIO_8021D_NC
;
343 priority
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
350 ASSERT(priority
>= 0 && priority
<= MAXPRIO
);
351 PKTSETPRIO(pkt
, priority
);
352 return (rc
| priority
);
355 /* lookup user priority for specified DSCP */
357 dscp2up(uint8
*up_table
, uint8 dscp
)
359 uint8 user_priority
= 255;
361 /* lookup up from table if parameters valid */
362 if (up_table
!= NULL
&& dscp
< UP_TABLE_MAX
) {
363 user_priority
= up_table
[dscp
];
366 /* 255 is unused value so return up from dscp */
367 if (user_priority
== 255) {
368 user_priority
= dscp
>> (IPV4_TOS_PREC_SHIFT
- IPV4_TOS_DSCP_SHIFT
);
371 return user_priority
;
374 /* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
376 pktsetprio_qms(void *pkt
, uint8
* up_table
, bool update_vtag
)
382 uint user_priority
= 0;
385 pktdata
= (uint8
*)PKTDATA(OSH_NULL
, pkt
);
386 pktlen
= PKTLEN(OSH_NULL
, pkt
);
388 if (pktgetdscp(pktdata
, pktlen
, &dscp
)) {
390 user_priority
= dscp2up(up_table
, dscp
);
391 PKTSETPRIO(pkt
, user_priority
);
394 return (rc
| user_priority
);
396 return pktsetprio(pkt
, update_vtag
);
400 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
403 pktgetdscp(uint8
*pktdata
, uint pktlen
, uint8
*dscp
)
405 struct ether_header
*eh
;
406 struct ethervlan_header
*evh
;
410 /* minimum length is ether header and IP header */
411 if (pktlen
< sizeof(struct ether_header
) + IPV4_MIN_HEADER_LEN
)
414 eh
= (struct ether_header
*) pktdata
;
416 if (eh
->ether_type
== HTON16(ETHER_TYPE_IP
)) {
417 ip_body
= pktdata
+ sizeof(struct ether_header
);
418 *dscp
= IP_DSCP46(ip_body
);
421 else if (eh
->ether_type
== HTON16(ETHER_TYPE_8021Q
)) {
422 evh
= (struct ethervlan_header
*)eh
;
424 /* minimum length is ethervlan header and IP header */
425 if (pktlen
>= sizeof(struct ethervlan_header
) + IPV4_MIN_HEADER_LEN
&&
426 evh
->ether_type
== HTON16(ETHER_TYPE_IP
)) {
427 ip_body
= pktdata
+ sizeof(struct ethervlan_header
);
428 *dscp
= IP_DSCP46(ip_body
);
436 /* usr_prio range from low to high with usr_prio value */
438 up_table_set(uint8
*up_table
, uint8 usr_prio
, uint8 low
, uint8 high
)
442 if (usr_prio
> 7 || low
> high
|| low
>= UP_TABLE_MAX
|| high
>= UP_TABLE_MAX
) {
446 for (i
= low
; i
<= high
; i
++) {
447 up_table
[i
] = usr_prio
;
453 /* set user priority table */
455 wl_set_up_table(uint8
*up_table
, bcm_tlv_t
*qos_map_ie
)
459 if (up_table
== NULL
|| qos_map_ie
== NULL
) {
463 /* clear table to check table was set or not */
464 memset(up_table
, 0xff, UP_TABLE_MAX
);
466 /* length of QoS Map IE must be 16+n*2, n is number of exceptions */
467 if (qos_map_ie
!= NULL
&& qos_map_ie
->id
== DOT11_MNG_QOS_MAP_ID
&&
468 (len
= qos_map_ie
->len
) >= QOS_MAP_FIXED_LENGTH
&&
470 uint8
*except_ptr
= (uint8
*)qos_map_ie
->data
;
471 uint8 except_len
= len
- QOS_MAP_FIXED_LENGTH
;
472 uint8
*range_ptr
= except_ptr
+ except_len
;
476 for (i
= 0; i
< QOS_MAP_FIXED_LENGTH
; i
+= 2) {
477 uint8 low
= range_ptr
[i
];
478 uint8 high
= range_ptr
[i
+ 1];
479 if (low
== 255 && high
== 255) {
483 if (!up_table_set(up_table
, i
/ 2, low
, high
)) {
484 /* clear the table on failure */
485 memset(up_table
, 0xff, UP_TABLE_MAX
);
490 /* update exceptions */
491 for (i
= 0; i
< except_len
; i
+= 2) {
492 uint8 dscp
= except_ptr
[i
];
493 uint8 usr_prio
= except_ptr
[i
+1];
495 /* exceptions with invalid dscp/usr_prio are ignored */
496 up_table_set(up_table
, usr_prio
, dscp
, dscp
);
503 /* The 0.5KB string table is not removed by compiler even though it's unused */
505 static char bcm_undeferrstr
[32];
506 static const char *bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
508 /* Convert the error codes into related error strings */
510 BCMRAMFN(bcmerrorstr
)(int bcmerror
)
512 /* check if someone added a bcmerror code but forgot to add errorstring */
513 ASSERT(ABS(BCME_LAST
) == (ARRAYSIZE(bcmerrorstrtable
) - 1));
515 if (bcmerror
> 0 || bcmerror
< BCME_LAST
) {
516 snprintf(bcm_undeferrstr
, sizeof(bcm_undeferrstr
), "Undefined error %d", bcmerror
);
517 return bcm_undeferrstr
;
520 ASSERT(strlen(bcmerrorstrtable
[-bcmerror
]) < BCME_STRLEN
);
522 return bcmerrorstrtable
[-bcmerror
];
525 /* iovar table lookup */
526 /* could mandate sorted tables and do a binary search */
528 bcm_iovar_lookup(const bcm_iovar_t
*table
, const char *name
)
530 const bcm_iovar_t
*vi
;
531 const char *lookup_name
;
533 /* skip any ':' delimited option prefixes */
534 lookup_name
= strrchr(name
, ':');
535 if (lookup_name
!= NULL
)
540 ASSERT(table
!= NULL
);
542 for (vi
= table
; vi
->name
; vi
++) {
543 if (!strcmp(vi
->name
, lookup_name
))
546 /* ran to end of table */
548 return NULL
; /* var name not found */
552 bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
557 /* length check on io buf */
566 /* all integers are int32 sized args at the ioctl interface */
567 if (len
< (int)sizeof(int)) {
568 bcmerror
= BCME_BUFTOOSHORT
;
573 /* buffer must meet minimum length requirement */
574 if (len
< vi
->minlen
) {
575 bcmerror
= BCME_BUFTOOSHORT
;
581 /* Cannot return nil... */
582 bcmerror
= BCME_UNSUPPORTED
;
587 /* unknown type for length check in iovar info */
589 bcmerror
= BCME_UNSUPPORTED
;
597 * Hierarchical Multiword bitmap based small id allocator.
599 * Multilevel hierarchy bitmap. (maximum 2 levels)
600 * First hierarchy uses a multiword bitmap to identify 32bit words in the
601 * second hierarchy that have at least a single bit set. Each bit in a word of
602 * the second hierarchy represents a unique ID that may be allocated.
604 * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
605 * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
606 * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
607 * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
608 * non-zero bitmap word carrying at least one free ID.
609 * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
610 * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
613 * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
614 * bits are computed each time on allocation and deallocation, requiring 4
615 * array indexed access and 3 arithmetic operations. When not defined, a runtime
616 * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
617 * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
618 * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
619 * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
621 * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
622 * size is fixed. No intention to support larger than 4K indice allocation. ID
623 * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
624 * with savings in not having to use an indirect access, had it been dynamically
627 #define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */
629 #define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
630 #define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
631 #define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
632 #define BCM_MWBMAP_SHIFT_OP (5)
633 #define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
634 #define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
635 #define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
637 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
638 #define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
639 #define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
641 #if defined(BCM_MWBMAP_DEBUG)
642 #define BCM_MWBMAP_AUDIT(mwb) \
644 ASSERT((mwb != NULL) && \
645 (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
646 bcm_mwbmap_audit(mwb); \
648 #define MWBMAP_ASSERT(exp) ASSERT(exp)
649 #define MWBMAP_DBG(x) printf x
650 #else /* !BCM_MWBMAP_DEBUG */
651 #define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
652 #define MWBMAP_ASSERT(exp) do {} while (0)
653 #define MWBMAP_DBG(x)
654 #endif /* !BCM_MWBMAP_DEBUG */
656 typedef struct bcm_mwbmap
{ /* Hierarchical multiword bitmap allocator */
657 uint16 wmaps
; /* Total number of words in free wd bitmap */
658 uint16 imaps
; /* Total number of words in free id bitmap */
659 int32 ifree
; /* Count of free indices. Used only in audits */
660 uint16 total
; /* Total indices managed by multiword bitmap */
662 void * magic
; /* Audit handle parameter from user */
664 uint32 wd_bitmap
[BCM_MWBMAP_WDMAP_MAX
]; /* 1st level bitmap of */
665 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
666 int8 wd_count
[BCM_MWBMAP_WORDS_MAX
]; /* free id running count, 1st lvl */
667 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
669 uint32 id_bitmap
[0]; /* Second level bitmap */
672 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
674 bcm_mwbmap_init(osl_t
*osh
, uint32 items_max
)
676 struct bcm_mwbmap
* mwbmap_p
;
677 uint32 wordix
, size
, words
, extra
;
679 /* Implementation Constraint: Uses 32bit word bitmap */
680 MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD
== 32U);
681 MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP
== 5U);
682 MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX
));
683 MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX
% BCM_MWBMAP_BITS_WORD
) == 0U);
685 ASSERT(items_max
<= BCM_MWBMAP_ITEMS_MAX
);
687 /* Determine the number of words needed in the multiword bitmap */
688 extra
= BCM_MWBMAP_MODOP(items_max
);
689 words
= BCM_MWBMAP_DIVOP(items_max
) + ((extra
!= 0U) ? 1U : 0U);
691 /* Allocate runtime state of multiword bitmap */
692 /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
693 size
= sizeof(bcm_mwbmap_t
) + (sizeof(uint32
) * words
);
694 mwbmap_p
= (bcm_mwbmap_t
*)MALLOC(osh
, size
);
695 if (mwbmap_p
== (bcm_mwbmap_t
*)NULL
) {
699 memset(mwbmap_p
, 0, size
);
701 /* Initialize runtime multiword bitmap state */
702 mwbmap_p
->imaps
= (uint16
)words
;
703 mwbmap_p
->ifree
= (int32
)items_max
;
704 mwbmap_p
->total
= (uint16
)items_max
;
706 /* Setup magic, for use in audit of handle */
707 mwbmap_p
->magic
= BCM_MWBMAP_HDL(mwbmap_p
);
709 /* Setup the second level bitmap of free indices */
710 /* Mark all indices as available */
711 for (wordix
= 0U; wordix
< mwbmap_p
->imaps
; wordix
++) {
712 mwbmap_p
->id_bitmap
[wordix
] = (uint32
)(~0U);
713 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
714 mwbmap_p
->wd_count
[wordix
] = BCM_MWBMAP_BITS_WORD
;
715 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
718 /* Ensure that extra indices are tagged as un-available */
719 if (extra
) { /* fixup the free ids in last bitmap and wd_count */
720 uint32
* bmap_p
= &mwbmap_p
->id_bitmap
[mwbmap_p
->imaps
- 1];
721 *bmap_p
^= (uint32
)(~0U << extra
); /* fixup bitmap */
722 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
723 mwbmap_p
->wd_count
[mwbmap_p
->imaps
- 1] = (int8
)extra
; /* fixup count */
724 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
727 /* Setup the first level bitmap hierarchy */
728 extra
= BCM_MWBMAP_MODOP(mwbmap_p
->imaps
);
729 words
= BCM_MWBMAP_DIVOP(mwbmap_p
->imaps
) + ((extra
!= 0U) ? 1U : 0U);
731 mwbmap_p
->wmaps
= (uint16
)words
;
733 for (wordix
= 0U; wordix
< mwbmap_p
->wmaps
; wordix
++)
734 mwbmap_p
->wd_bitmap
[wordix
] = (uint32
)(~0U);
736 uint32
* bmap_p
= &mwbmap_p
->wd_bitmap
[mwbmap_p
->wmaps
- 1];
737 *bmap_p
^= (uint32
)(~0U << extra
); /* fixup bitmap */
743 return BCM_MWBMAP_INVALID_HDL
;
746 /* Release resources used by multiword bitmap based small index allocator. */
748 bcm_mwbmap_fini(osl_t
* osh
, struct bcm_mwbmap
* mwbmap_hdl
)
750 bcm_mwbmap_t
* mwbmap_p
;
752 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
753 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
755 MFREE(osh
, mwbmap_p
, sizeof(struct bcm_mwbmap
)
756 + (sizeof(uint32
) * mwbmap_p
->imaps
));
760 /* Allocate a unique small index using a multiword bitmap index allocator. */
762 bcm_mwbmap_alloc(struct bcm_mwbmap
* mwbmap_hdl
)
764 bcm_mwbmap_t
* mwbmap_p
;
765 uint32 wordix
, bitmap
;
767 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
768 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
770 /* Start with the first hierarchy */
771 for (wordix
= 0; wordix
< mwbmap_p
->wmaps
; ++wordix
) {
773 bitmap
= mwbmap_p
->wd_bitmap
[wordix
]; /* get the word bitmap */
777 uint32 count
, bitix
, *bitmap_p
;
779 bitmap_p
= &mwbmap_p
->wd_bitmap
[wordix
];
781 /* clear all except trailing 1 */
782 bitmap
= (uint32
)(((int)(bitmap
)) & (-((int)(bitmap
))));
783 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap
) ==
784 bcm_count_leading_zeros(bitmap
));
785 bitix
= (BCM_MWBMAP_BITS_WORD
- 1)
786 - bcm_count_leading_zeros(bitmap
); /* use asm clz */
787 wordix
= BCM_MWBMAP_MULOP(wordix
) + bitix
;
789 /* Clear bit if wd count is 0, without conditional branch */
790 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
791 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[wordix
]) - 1;
792 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
793 mwbmap_p
->wd_count
[wordix
]--;
794 count
= mwbmap_p
->wd_count
[wordix
];
795 MWBMAP_ASSERT(count
==
796 (bcm_cntsetbits(mwbmap_p
->id_bitmap
[wordix
]) - 1));
797 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
798 MWBMAP_ASSERT(count
>= 0);
800 /* clear wd_bitmap bit if id_map count is 0 */
801 bitmap
= (count
== 0) << bitix
;
804 "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
805 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) ^ bitmap
, count
));
809 /* Use bitix in the second hierarchy */
810 bitmap_p
= &mwbmap_p
->id_bitmap
[wordix
];
812 bitmap
= mwbmap_p
->id_bitmap
[wordix
]; /* get the id bitmap */
813 MWBMAP_ASSERT(bitmap
!= 0U);
815 /* clear all except trailing 1 */
816 bitmap
= (uint32
)(((int)(bitmap
)) & (-((int)(bitmap
))));
817 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap
) ==
818 bcm_count_leading_zeros(bitmap
));
819 bitix
= BCM_MWBMAP_MULOP(wordix
)
820 + (BCM_MWBMAP_BITS_WORD
- 1)
821 - bcm_count_leading_zeros(bitmap
); /* use asm clz */
823 mwbmap_p
->ifree
--; /* decrement system wide free count */
824 MWBMAP_ASSERT(mwbmap_p
->ifree
>= 0);
827 "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
828 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) ^ bitmap
,
831 *bitmap_p
^= bitmap
; /* mark as allocated = 1b0 */
837 ASSERT(mwbmap_p
->ifree
== 0);
839 return BCM_MWBMAP_INVALID_IDX
;
842 /* Force an index at a specified position to be in use */
844 bcm_mwbmap_force(struct bcm_mwbmap
* mwbmap_hdl
, uint32 bitix
)
846 bcm_mwbmap_t
* mwbmap_p
;
847 uint32 count
, wordix
, bitmap
, *bitmap_p
;
849 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
850 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
852 ASSERT(bitix
< mwbmap_p
->total
);
854 /* Start with second hierarchy */
855 wordix
= BCM_MWBMAP_DIVOP(bitix
);
856 bitmap
= (uint32
)(1U << BCM_MWBMAP_MODOP(bitix
));
857 bitmap_p
= &mwbmap_p
->id_bitmap
[wordix
];
859 ASSERT((*bitmap_p
& bitmap
) == bitmap
);
861 mwbmap_p
->ifree
--; /* update free count */
862 ASSERT(mwbmap_p
->ifree
>= 0);
864 MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
865 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) ^ bitmap
,
868 *bitmap_p
^= bitmap
; /* mark as in use */
870 /* Update first hierarchy */
873 wordix
= BCM_MWBMAP_DIVOP(bitix
);
874 bitmap_p
= &mwbmap_p
->wd_bitmap
[wordix
];
876 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
877 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[bitix
]);
878 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
879 mwbmap_p
->wd_count
[bitix
]--;
880 count
= mwbmap_p
->wd_count
[bitix
];
881 MWBMAP_ASSERT(count
== bcm_cntsetbits(mwbmap_p
->id_bitmap
[bitix
]));
882 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
883 MWBMAP_ASSERT(count
>= 0);
885 bitmap
= (count
== 0) << BCM_MWBMAP_MODOP(bitix
);
887 MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
888 BCM_MWBMAP_MODOP(bitix
), wordix
, *bitmap_p
, bitmap
,
889 (*bitmap_p
) ^ bitmap
, count
));
891 *bitmap_p
^= bitmap
; /* mark as in use */
896 /* Free a previously allocated index back into the multiword bitmap allocator */
898 bcm_mwbmap_free(struct bcm_mwbmap
* mwbmap_hdl
, uint32 bitix
)
900 bcm_mwbmap_t
* mwbmap_p
;
901 uint32 wordix
, bitmap
, *bitmap_p
;
903 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
904 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
906 ASSERT(bitix
< mwbmap_p
->total
);
908 /* Start with second level hierarchy */
909 wordix
= BCM_MWBMAP_DIVOP(bitix
);
910 bitmap
= (1U << BCM_MWBMAP_MODOP(bitix
));
911 bitmap_p
= &mwbmap_p
->id_bitmap
[wordix
];
913 ASSERT((*bitmap_p
& bitmap
) == 0U); /* ASSERT not a double free */
915 mwbmap_p
->ifree
++; /* update free count */
916 ASSERT(mwbmap_p
->ifree
<= mwbmap_p
->total
);
918 MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
919 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) | bitmap
,
922 *bitmap_p
|= bitmap
; /* mark as available */
924 /* Now update first level hierarchy */
928 wordix
= BCM_MWBMAP_DIVOP(bitix
); /* first level's word index */
929 bitmap
= (1U << BCM_MWBMAP_MODOP(bitix
));
930 bitmap_p
= &mwbmap_p
->wd_bitmap
[wordix
];
932 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
933 mwbmap_p
->wd_count
[bitix
]++;
936 #if defined(BCM_MWBMAP_DEBUG)
939 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
940 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[bitix
]);
941 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
942 count
= mwbmap_p
->wd_count
[bitix
];
943 MWBMAP_ASSERT(count
== bcm_cntsetbits(mwbmap_p
->id_bitmap
[bitix
]));
944 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
946 MWBMAP_ASSERT(count
<= BCM_MWBMAP_BITS_WORD
);
948 MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
949 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) | bitmap
, count
));
951 #endif /* BCM_MWBMAP_DEBUG */
958 /* Fetch the toal number of free indices in the multiword bitmap allocator */
960 bcm_mwbmap_free_cnt(struct bcm_mwbmap
* mwbmap_hdl
)
962 bcm_mwbmap_t
* mwbmap_p
;
964 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
965 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
967 ASSERT(mwbmap_p
->ifree
>= 0);
969 return mwbmap_p
->ifree
;
972 /* Determine whether an index is inuse or free */
974 bcm_mwbmap_isfree(struct bcm_mwbmap
* mwbmap_hdl
, uint32 bitix
)
976 bcm_mwbmap_t
* mwbmap_p
;
977 uint32 wordix
, bitmap
;
979 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
980 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
982 ASSERT(bitix
< mwbmap_p
->total
);
984 wordix
= BCM_MWBMAP_DIVOP(bitix
);
985 bitmap
= (1U << BCM_MWBMAP_MODOP(bitix
));
987 return ((mwbmap_p
->id_bitmap
[wordix
] & bitmap
) != 0U);
990 /* Debug dump a multiword bitmap allocator */
992 bcm_mwbmap_show(struct bcm_mwbmap
* mwbmap_hdl
)
995 bcm_mwbmap_t
* mwbmap_p
;
997 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
998 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
1000 printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n",
1001 OSL_OBFUSCATE_BUF((void *)mwbmap_p
),
1002 mwbmap_p
->wmaps
, mwbmap_p
->imaps
, mwbmap_p
->ifree
, mwbmap_p
->total
);
1003 for (ix
= 0U; ix
< mwbmap_p
->wmaps
; ix
++) {
1004 printf("\tWDMAP:%2u. 0x%08x\t", ix
, mwbmap_p
->wd_bitmap
[ix
]);
1005 bcm_bitprint32(mwbmap_p
->wd_bitmap
[ix
]);
1008 for (ix
= 0U; ix
< mwbmap_p
->imaps
; ix
++) {
1009 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
1010 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[ix
]);
1011 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
1012 count
= mwbmap_p
->wd_count
[ix
];
1013 MWBMAP_ASSERT(count
== bcm_cntsetbits(mwbmap_p
->id_bitmap
[ix
]));
1014 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1015 printf("\tIDMAP:%2u. 0x%08x %02u\t", ix
, mwbmap_p
->id_bitmap
[ix
], count
);
1016 bcm_bitprint32(mwbmap_p
->id_bitmap
[ix
]);
1023 /* Audit a hierarchical multiword bitmap */
1025 bcm_mwbmap_audit(struct bcm_mwbmap
* mwbmap_hdl
)
1027 bcm_mwbmap_t
* mwbmap_p
;
1028 uint32 count
, free_cnt
= 0U, wordix
, idmap_ix
, bitix
, *bitmap_p
;
1030 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
1032 for (wordix
= 0U; wordix
< mwbmap_p
->wmaps
; ++wordix
) {
1034 bitmap_p
= &mwbmap_p
->wd_bitmap
[wordix
];
1036 for (bitix
= 0U; bitix
< BCM_MWBMAP_BITS_WORD
; bitix
++) {
1037 if ((*bitmap_p
) & (1 << bitix
)) {
1038 idmap_ix
= BCM_MWBMAP_MULOP(wordix
) + bitix
;
1039 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
1040 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[idmap_ix
]);
1041 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
1042 count
= mwbmap_p
->wd_count
[idmap_ix
];
1043 ASSERT(count
== bcm_cntsetbits(mwbmap_p
->id_bitmap
[idmap_ix
]));
1044 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1045 ASSERT(count
!= 0U);
1051 ASSERT((int)free_cnt
== mwbmap_p
->ifree
);
1053 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
1055 /* Simple 16bit Id allocator using a stack implementation. */
1056 typedef struct id16_map
{
1057 uint32 failures
; /* count of failures */
1058 void *dbg
; /* debug placeholder */
1059 uint16 total
; /* total number of ids managed by allocator */
1060 uint16 start
; /* start value of 16bit ids to be managed */
1061 int stack_idx
; /* index into stack of available ids */
1062 uint16 stack
[0]; /* stack of 16 bit ids */
1065 #define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \
1066 (sizeof(uint16) * (items)))
1068 #if defined(BCM_DBG)
1070 /* Uncomment BCM_DBG_ID16 to debug double free */
1071 /* #define BCM_DBG_ID16 */
1073 typedef struct id16_map_dbg
{
1077 #define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \
1078 (sizeof(bool) * (items)))
1079 #define ID16_MAP_MSG(x) print x
1081 #define ID16_MAP_MSG(x)
1082 #endif /* BCM_DBG */
1084 void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
1085 id16_map_init(osl_t
*osh
, uint16 total_ids
, uint16 start_val16
)
1088 id16_map_t
* id16_map
;
1090 ASSERT(total_ids
> 0);
1092 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
1093 * with random values.
1095 ASSERT((start_val16
== ID16_UNDEFINED
) ||
1096 (start_val16
+ total_ids
) < ID16_INVALID
);
1098 id16_map
= (id16_map_t
*) MALLOC(osh
, ID16_MAP_SZ(total_ids
));
1099 if (id16_map
== NULL
) {
1103 id16_map
->total
= total_ids
;
1104 id16_map
->start
= start_val16
;
1105 id16_map
->failures
= 0;
1106 id16_map
->dbg
= NULL
;
1109 * Populate stack with 16bit id values, commencing with start_val16.
1110 * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
1112 id16_map
->stack_idx
= -1;
1114 if (id16_map
->start
!= ID16_UNDEFINED
) {
1115 val16
= start_val16
;
1117 for (idx
= 0; idx
< total_ids
; idx
++, val16
++) {
1118 id16_map
->stack_idx
= idx
;
1119 id16_map
->stack
[id16_map
->stack_idx
] = val16
;
1123 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1124 if (id16_map
->start
!= ID16_UNDEFINED
) {
1125 id16_map
->dbg
= MALLOC(osh
, ID16_MAP_DBG_SZ(total_ids
));
1127 if (id16_map
->dbg
) {
1128 id16_map_dbg_t
*id16_map_dbg
= (id16_map_dbg_t
*)id16_map
->dbg
;
1130 id16_map_dbg
->total
= total_ids
;
1131 for (idx
= 0; idx
< total_ids
; idx
++) {
1132 id16_map_dbg
->avail
[idx
] = TRUE
;
1136 #endif /* BCM_DBG && BCM_DBG_ID16 */
1138 return (void *)id16_map
;
1141 void * /* Destruct an id16 allocator instance */
1142 id16_map_fini(osl_t
*osh
, void * id16_map_hndl
)
1145 id16_map_t
* id16_map
;
1147 if (id16_map_hndl
== NULL
)
1150 id16_map
= (id16_map_t
*)id16_map_hndl
;
1152 total_ids
= id16_map
->total
;
1153 ASSERT(total_ids
> 0);
1155 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1156 if (id16_map
->dbg
) {
1157 MFREE(osh
, id16_map
->dbg
, ID16_MAP_DBG_SZ(total_ids
));
1158 id16_map
->dbg
= NULL
;
1160 #endif /* BCM_DBG && BCM_DBG_ID16 */
1162 id16_map
->total
= 0;
1163 MFREE(osh
, id16_map
, ID16_MAP_SZ(total_ids
));
1169 id16_map_clear(void * id16_map_hndl
, uint16 total_ids
, uint16 start_val16
)
1172 id16_map_t
* id16_map
;
1174 ASSERT(total_ids
> 0);
1175 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
1176 * with random values.
1178 ASSERT((start_val16
== ID16_UNDEFINED
) ||
1179 (start_val16
+ total_ids
) < ID16_INVALID
);
1181 id16_map
= (id16_map_t
*)id16_map_hndl
;
1182 if (id16_map
== NULL
) {
1186 id16_map
->total
= total_ids
;
1187 id16_map
->start
= start_val16
;
1188 id16_map
->failures
= 0;
1190 /* Populate stack with 16bit id values, commencing with start_val16 */
1191 id16_map
->stack_idx
= -1;
1193 if (id16_map
->start
!= ID16_UNDEFINED
) {
1194 val16
= start_val16
;
1196 for (idx
= 0; idx
< total_ids
; idx
++, val16
++) {
1197 id16_map
->stack_idx
= idx
;
1198 id16_map
->stack
[id16_map
->stack_idx
] = val16
;
1202 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1203 if (id16_map
->start
!= ID16_UNDEFINED
) {
1204 if (id16_map
->dbg
) {
1205 id16_map_dbg_t
*id16_map_dbg
= (id16_map_dbg_t
*)id16_map
->dbg
;
1207 id16_map_dbg
->total
= total_ids
;
1208 for (idx
= 0; idx
< total_ids
; idx
++) {
1209 id16_map_dbg
->avail
[idx
] = TRUE
;
1213 #endif /* BCM_DBG && BCM_DBG_ID16 */
1216 uint16 BCMFASTPATH
/* Allocate a unique 16bit id */
1217 id16_map_alloc(void * id16_map_hndl
)
1220 id16_map_t
* id16_map
;
1222 ASSERT(id16_map_hndl
!= NULL
);
1224 id16_map
= (id16_map_t
*)id16_map_hndl
;
1226 ASSERT(id16_map
->total
> 0);
1228 if (id16_map
->stack_idx
< 0) {
1229 id16_map
->failures
++;
1230 return ID16_INVALID
;
1233 val16
= id16_map
->stack
[id16_map
->stack_idx
];
1234 id16_map
->stack_idx
--;
1236 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1237 ASSERT((id16_map
->start
== ID16_UNDEFINED
) ||
1238 (val16
< (id16_map
->start
+ id16_map
->total
)));
1240 if (id16_map
->dbg
) { /* Validate val16 */
1241 id16_map_dbg_t
*id16_map_dbg
= (id16_map_dbg_t
*)id16_map
->dbg
;
1243 ASSERT(id16_map_dbg
->avail
[val16
- id16_map
->start
] == TRUE
);
1244 id16_map_dbg
->avail
[val16
- id16_map
->start
] = FALSE
;
1246 #endif /* BCM_DBG && BCM_DBG_ID16 */
1251 void BCMFASTPATH
/* Free a 16bit id value into the id16 allocator */
1252 id16_map_free(void * id16_map_hndl
, uint16 val16
)
1254 id16_map_t
* id16_map
;
1256 ASSERT(id16_map_hndl
!= NULL
);
1258 id16_map
= (id16_map_t
*)id16_map_hndl
;
1260 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1261 ASSERT((id16_map
->start
== ID16_UNDEFINED
) ||
1262 (val16
< (id16_map
->start
+ id16_map
->total
)));
1264 if (id16_map
->dbg
) { /* Validate val16 */
1265 id16_map_dbg_t
*id16_map_dbg
= (id16_map_dbg_t
*)id16_map
->dbg
;
1267 ASSERT(id16_map_dbg
->avail
[val16
- id16_map
->start
] == FALSE
);
1268 id16_map_dbg
->avail
[val16
- id16_map
->start
] = TRUE
;
1270 #endif /* BCM_DBG && BCM_DBG_ID16 */
1272 id16_map
->stack_idx
++;
1273 id16_map
->stack
[id16_map
->stack_idx
] = val16
;
1276 uint32
/* Returns number of failures to allocate an unique id16 */
1277 id16_map_failures(void * id16_map_hndl
)
1279 ASSERT(id16_map_hndl
!= NULL
);
1280 return ((id16_map_t
*)id16_map_hndl
)->failures
;
1284 id16_map_audit(void * id16_map_hndl
)
1288 id16_map_t
* id16_map
;
1290 ASSERT(id16_map_hndl
!= NULL
);
1292 id16_map
= (id16_map_t
*)id16_map_hndl
;
1294 ASSERT(id16_map
->stack_idx
>= -1);
1295 ASSERT(id16_map
->stack_idx
< (int)id16_map
->total
);
1297 if (id16_map
->start
== ID16_UNDEFINED
)
1300 for (idx
= 0; idx
<= id16_map
->stack_idx
; idx
++) {
1301 ASSERT(id16_map
->stack
[idx
] >= id16_map
->start
);
1302 ASSERT(id16_map
->stack
[idx
] < (id16_map
->start
+ id16_map
->total
));
1304 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1305 if (id16_map
->dbg
) {
1306 uint16 val16
= id16_map
->stack
[idx
];
1307 if (((id16_map_dbg_t
*)(id16_map
->dbg
))->avail
[val16
] != TRUE
) {
1309 ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
1310 OSL_OBFUSATE_BUF(id16_map_hndl
), idx
, val16
));
1313 #endif /* BCM_DBG && BCM_DBG_ID16 */
1316 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1317 if (id16_map
->dbg
) {
1318 uint16 avail
= 0; /* Audit available ids counts */
1319 for (idx
= 0; idx
< id16_map_dbg
->total
; idx
++) {
1320 if (((id16_map_dbg_t
*)(id16_map
->dbg
))->avail
[idx16
] == TRUE
)
1323 if (avail
&& (avail
!= (id16_map
->stack_idx
+ 1))) {
1325 ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
1326 OSL_OBFUSCATE_BUF(id16_map_hndl
),
1327 avail
, id16_map
->stack_idx
));
1330 #endif /* BCM_DBG && BCM_DBG_ID16 */
1333 /* invoke any other system audits */
1336 /* END: Simple id16 allocator */
1339 dll_pool_detach(void * osh
, dll_pool_t
* pool
, uint16 elems_max
, uint16 elem_size
)
1342 mem_size
= sizeof(dll_pool_t
) + (elems_max
* elem_size
);
1344 MFREE(osh
, pool
, mem_size
);
1347 dll_pool_init(void * osh
, uint16 elems_max
, uint16 elem_size
)
1350 dll_pool_t
* dll_pool_p
;
1353 ASSERT(elem_size
> sizeof(dll_t
));
1355 mem_size
= sizeof(dll_pool_t
) + (elems_max
* elem_size
);
1357 if ((dll_pool_p
= (dll_pool_t
*)MALLOCZ(osh
, mem_size
)) == NULL
) {
1358 printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
1359 elems_max
, elem_size
);
1364 dll_init(&dll_pool_p
->free_list
);
1365 dll_pool_p
->elems_max
= elems_max
;
1366 dll_pool_p
->elem_size
= elem_size
;
1368 elem_p
= dll_pool_p
->elements
;
1369 for (i
= 0; i
< elems_max
; i
++) {
1370 dll_append(&dll_pool_p
->free_list
, elem_p
);
1371 elem_p
= (dll_t
*)((uintptr
)elem_p
+ elem_size
);
1374 dll_pool_p
->free_count
= elems_max
;
1380 dll_pool_alloc(dll_pool_t
* dll_pool_p
)
1384 if (dll_pool_p
->free_count
== 0) {
1385 ASSERT(dll_empty(&dll_pool_p
->free_list
));
1389 elem_p
= dll_head_p(&dll_pool_p
->free_list
);
1391 dll_pool_p
->free_count
-= 1;
1393 return (void *)elem_p
;
1397 dll_pool_free(dll_pool_t
* dll_pool_p
, void * elem_p
)
1399 dll_t
* node_p
= (dll_t
*)elem_p
;
1400 dll_prepend(&dll_pool_p
->free_list
, node_p
);
1401 dll_pool_p
->free_count
+= 1;
1405 dll_pool_free_tail(dll_pool_t
* dll_pool_p
, void * elem_p
)
1407 dll_t
* node_p
= (dll_t
*)elem_p
;
1408 dll_append(&dll_pool_p
->free_list
, node_p
);
1409 dll_pool_p
->free_count
+= 1;
1414 #endif /* BCMDRIVER */
1416 #if defined(BCMDRIVER) || defined(WL_UNITTEST)
1418 /* triggers bcm_bprintf to print to kernel log */
1419 bool bcm_bprintf_bypass
= FALSE
;
1421 /* Initialization of bcmstrbuf structure */
1423 bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
1425 b
->origsize
= b
->size
= size
;
1426 b
->origbuf
= b
->buf
= buf
;
1432 /* Buffer sprintf wrapper to guard against buffer overflow */
1434 bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
1441 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
1442 if (bcm_bprintf_bypass
== TRUE
) {
1443 printf("%s", b
->buf
);
1447 /* Non Ansi C99 compliant returns -1,
1448 * Ansi compliant return r >= b->size,
1449 * bcmstdlib returns 0, handle all
1451 /* r == 0 is also the case when strlen(fmt) is zero.
1452 * typically the case when "" is passed as argument.
1454 if ((r
== -1) || (r
>= (int)b
->size
)) {
1468 bcm_bprhex(struct bcmstrbuf
*b
, const char *msg
, bool newline
, const uint8
*buf
, int len
)
1472 if (msg
!= NULL
&& msg
[0] != '\0')
1473 bcm_bprintf(b
, "%s", msg
);
1474 for (i
= 0; i
< len
; i
++)
1475 bcm_bprintf(b
, "%02X", buf
[i
]);
1477 bcm_bprintf(b
, "\n");
1481 bcm_inc_bytes(uchar
*num
, int num_bytes
, uint8 amount
)
1485 for (i
= 0; i
< num_bytes
; i
++) {
1487 if (num
[i
] >= amount
)
1494 bcm_cmp_bytes(const uchar
*arg1
, const uchar
*arg2
, uint8 nbytes
)
1498 for (i
= nbytes
- 1; i
>= 0; i
--) {
1499 if (arg1
[i
] != arg2
[i
])
1500 return (arg1
[i
] - arg2
[i
]);
1506 bcm_print_bytes(const char *name
, const uchar
*data
, int len
)
1511 printf("%s: %d \n", name
? name
: "", len
);
1512 for (i
= 0; i
< len
; i
++) {
1513 printf("%02x ", *data
++);
1515 if (per_line
== 16) {
1523 /* Look for vendor-specific IE with specified OUI and optional type */
1525 bcm_find_vendor_ie(const void *tlvs
, uint tlvs_len
, const char *voui
, uint8
*type
, uint type_len
)
1527 const bcm_tlv_t
*ie
;
1530 ie
= (const bcm_tlv_t
*)tlvs
;
1532 /* make sure we are looking at a valid IE */
1533 if (ie
== NULL
|| !bcm_valid_tlv(ie
, tlvs_len
)) {
1537 /* Walk through the IEs looking for an OUI match */
1540 if ((ie
->id
== DOT11_MNG_VS_ID
) &&
1541 (ie_len
>= (DOT11_OUI_LEN
+ type_len
)) &&
1542 !bcmp(ie
->data
, voui
, DOT11_OUI_LEN
))
1544 /* compare optional type */
1545 if (type_len
== 0 ||
1546 !bcmp(&ie
->data
[DOT11_OUI_LEN
], type
, type_len
)) {
1547 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1548 return (bcm_tlv_t
*)(ie
); /* a match */
1549 GCC_DIAGNOSTIC_POP();
1552 } while ((ie
= bcm_next_tlv(ie
, &tlvs_len
)) != NULL
);
1557 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1558 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1559 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1562 bcm_format_ssid(char* buf
, const uchar ssid
[], uint ssid_len
)
1566 char *endp
= buf
+ SSID_FMT_BUF_LEN
;
1568 if (ssid_len
> DOT11_MAX_SSID_LEN
) ssid_len
= DOT11_MAX_SSID_LEN
;
1570 for (i
= 0; i
< ssid_len
; i
++) {
1575 } else if (bcm_isprint((uchar
)c
)) {
1578 p
+= snprintf(p
, (endp
- p
), "\\x%02X", c
);
1584 return (int)(p
- buf
);
1588 #endif /* BCMDRIVER || WL_UNITTEST */
1591 bcm_ether_ntoa(const struct ether_addr
*ea
, char *buf
)
1593 static const char hex
[] =
1595 '0', '1', '2', '3', '4', '5', '6', '7',
1596 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1598 const uint8
*octet
= ea
->octet
;
1602 for (i
= 0; i
< 6; i
++, octet
++) {
1603 *p
++ = hex
[(*octet
>> 4) & 0xf];
1604 *p
++ = hex
[*octet
& 0xf];
1613 /* Find the position of first bit set
1614 * in the given number.
1617 bcm_find_fsb(uint32 num
)
1622 while (!(num
& 1)) {
1630 bcm_ip_ntoa(struct ipv4_addr
*ia
, char *buf
)
1632 snprintf(buf
, 16, "%d.%d.%d.%d",
1633 ia
->addr
[0], ia
->addr
[1], ia
->addr
[2], ia
->addr
[3]);
1638 bcm_ipv6_ntoa(void *ipv6
, char *buf
)
1640 /* Implementing RFC 5952 Sections 4 + 5 */
1641 /* Not thoroughly tested */
1643 uint16
*a
= &tmp
[0];
1645 int i
, i_max
= -1, cnt
= 0, cnt_max
= 1;
1647 memcpy((uint8
*)&tmp
[0], (uint8
*)ipv6
, IPV6_ADDR_LEN
);
1649 for (i
= 0; i
< IPV6_ADDR_LEN
/2; i
++) {
1651 if (cnt
> cnt_max
) {
1659 if (cnt
> cnt_max
) {
1664 /* IPv4-translated: ::ffff:0:a.b.c.d */
1665 ((cnt_max
== 4 && a
[4] == 0xffff && a
[5] == 0) ||
1666 /* IPv4-mapped: ::ffff:a.b.c.d */
1667 (cnt_max
== 5 && a
[5] == 0xffff)))
1668 a4
= (uint8
*) (a
+ 6);
1670 for (i
= 0; i
< IPV6_ADDR_LEN
/2; i
++) {
1671 if ((uint8
*) (a
+ i
) == a4
) {
1672 snprintf(p
, 16, ":%u.%u.%u.%u", a4
[0], a4
[1], a4
[2], a4
[3]);
1674 } else if (i
== i_max
) {
1682 p
+= snprintf(p
, 8, "%x", ntoh16(a
[i
]));
1689 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
1690 const unsigned char bcm_ctype
[] = {
1692 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 0-7 */
1693 _BCM_C
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
,
1695 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 16-23 */
1696 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 24-31 */
1697 _BCM_S
|_BCM_SP
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 32-39 */
1698 _BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 40-47 */
1699 _BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
, /* 48-55 */
1700 _BCM_D
,_BCM_D
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 56-63 */
1701 _BCM_P
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
,
1702 _BCM_U
|_BCM_X
, _BCM_U
, /* 64-71 */
1703 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 72-79 */
1704 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 80-87 */
1705 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 88-95 */
1706 _BCM_P
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
,
1707 _BCM_L
|_BCM_X
, _BCM_L
, /* 96-103 */
1708 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 104-111 */
1709 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 112-119 */
1710 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_C
, /* 120-127 */
1711 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
1712 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
1713 _BCM_S
|_BCM_SP
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
1714 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 160-175 */
1715 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
1716 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 176-191 */
1717 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
,
1718 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, /* 192-207 */
1719 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_P
, _BCM_U
, _BCM_U
, _BCM_U
,
1720 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_L
, /* 208-223 */
1721 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
,
1722 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, /* 224-239 */
1723 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_P
, _BCM_L
, _BCM_L
, _BCM_L
,
1724 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
/* 240-255 */
1728 bcm_strtoull(const char *cp
, char **endp
, uint base
)
1730 uint64 result
, last_result
= 0, value
;
1735 while (bcm_isspace(*cp
))
1740 else if (cp
[0] == '-') {
1747 if ((cp
[1] == 'x') || (cp
[1] == 'X')) {
1756 } else if (base
== 16 && (cp
[0] == '0') && ((cp
[1] == 'x') || (cp
[1] == 'X'))) {
1762 while (bcm_isxdigit(*cp
) &&
1763 (value
= bcm_isdigit(*cp
) ? *cp
-'0' : bcm_toupper(*cp
)-'A'+10) < base
) {
1764 result
= result
*base
+ value
;
1765 /* Detected overflow */
1766 if (result
< last_result
&& !minus
) {
1768 /* Go to the end of current number */
1769 while (bcm_isxdigit(*cp
)) {
1772 *endp
= DISCARD_QUAL(cp
, char);
1776 last_result
= result
;
1781 result
= (ulong
)(-(long)result
);
1784 *endp
= DISCARD_QUAL(cp
, char);
1790 bcm_strtoul(const char *cp
, char **endp
, uint base
)
1792 return (ulong
) bcm_strtoull(cp
, endp
, base
);
1796 bcm_atoi(const char *s
)
1798 return (int)bcm_strtoul(s
, NULL
, 10);
1801 /* return pointer to location of substring 'needle' in 'haystack' */
1803 bcmstrstr(const char *haystack
, const char *needle
)
1808 if ((haystack
== NULL
) || (needle
== NULL
))
1809 return DISCARD_QUAL(haystack
, char);
1811 nlen
= (int)strlen(needle
);
1812 len
= (int)strlen(haystack
) - nlen
+ 1;
1814 for (i
= 0; i
< len
; i
++)
1815 if (memcmp(needle
, &haystack
[i
], nlen
) == 0)
1816 return DISCARD_QUAL(&haystack
[i
], char);
1821 bcmstrnstr(const char *s
, uint s_len
, const char *substr
, uint substr_len
)
1823 for (; s_len
>= substr_len
; s
++, s_len
--)
1824 if (strncmp(s
, substr
, substr_len
) == 0)
1825 return DISCARD_QUAL(s
, char);
1831 bcmstrcat(char *dest
, const char *src
)
1835 p
= dest
+ strlen(dest
);
1837 while ((*p
++ = *src
++) != '\0')
1844 bcmstrncat(char *dest
, const char *src
, uint size
)
1849 p
= dest
+ strlen(dest
);
1852 while (p
!= endp
&& (*p
++ = *src
++) != '\0')
1858 /****************************************************************************
1859 * Function: bcmstrtok
1862 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
1863 * but allows strToken() to be used by different strings or callers at the same
1864 * time. Each call modifies '*string' by substituting a NULL character for the
1865 * first delimiter that is encountered, and updates 'string' to point to the char
1866 * after the delimiter. Leading delimiters are skipped.
1869 * string (mod) Ptr to string ptr, updated by token.
1870 * delimiters (in) Set of delimiter characters.
1871 * tokdelim (out) Character that delimits the returned token. (May
1872 * be set to NULL if token delimiter is not required).
1874 * Returns: Pointer to the next token found. NULL when no more tokens are found.
1875 *****************************************************************************
1878 bcmstrtok(char **string
, const char *delimiters
, char *tokdelim
)
1881 unsigned long map
[8];
1885 if (tokdelim
!= NULL
) {
1886 /* Prime the token delimiter */
1890 /* Clear control map */
1891 for (count
= 0; count
< 8; count
++) {
1895 /* Set bits in delimiter table */
1897 map
[*delimiters
>> 5] |= (1 << (*delimiters
& 31));
1899 while (*delimiters
++);
1901 str
= (unsigned char*)*string
;
1903 /* Find beginning of token (skip over leading delimiters). Note that
1904 * there is no token iff this loop sets str to point to the terminal
1905 * null (*str == '\0')
1907 while (((map
[*str
>> 5] & (1 << (*str
& 31))) && *str
) || (*str
== ' ')) {
1911 nextoken
= (char*)str
;
1913 /* Find the end of the token. If it is not the end of the string,
1916 for (; *str
; str
++) {
1917 if (map
[*str
>> 5] & (1 << (*str
& 31))) {
1918 if (tokdelim
!= NULL
) {
1927 *string
= (char*)str
;
1929 /* Determine if a token has been found. */
1930 if (nextoken
== (char *) str
) {
1938 #define xToLower(C) \
1939 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
1941 /****************************************************************************
1942 * Function: bcmstricmp
1944 * Purpose: Compare to strings case insensitively.
1946 * Parameters: s1 (in) First string to compare.
1947 * s2 (in) Second string to compare.
1949 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1950 * t1 > t2, when ignoring case sensitivity.
1951 *****************************************************************************
1954 bcmstricmp(const char *s1
, const char *s2
)
1958 while (*s2
&& *s1
) {
1961 if (dc
< sc
) return -1;
1962 if (dc
> sc
) return 1;
1967 if (*s1
&& !*s2
) return 1;
1968 if (!*s1
&& *s2
) return -1;
1972 /****************************************************************************
1973 * Function: bcmstrnicmp
1975 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
1978 * Parameters: s1 (in) First string to compare.
1979 * s2 (in) Second string to compare.
1980 * cnt (in) Max characters to compare.
1982 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1983 * t1 > t2, when ignoring case sensitivity.
1984 *****************************************************************************
1987 bcmstrnicmp(const char* s1
, const char* s2
, int cnt
)
1991 while (*s2
&& *s1
&& cnt
) {
1994 if (dc
< sc
) return -1;
1995 if (dc
> sc
) return 1;
2002 if (*s1
&& !*s2
) return 1;
2003 if (!*s1
&& *s2
) return -1;
2007 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
2009 bcm_ether_atoe(const char *p
, struct ether_addr
*ea
)
2015 ea
->octet
[i
++] = (char) bcm_strtoul(p
, &ep
, 16);
2017 if (!*p
++ || i
== 6)
2025 bcm_atoipv4(const char *p
, struct ipv4_addr
*ip
)
2031 ip
->addr
[i
++] = (uint8
)bcm_strtoul(p
, &c
, 0);
2032 if (*c
++ != '.' || i
== IPV4_ADDR_LEN
)
2036 return (i
== IPV4_ADDR_LEN
);
2038 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
2040 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
2041 /* registry routine buffer preparation utility functions:
2042 * parameter order is like strncpy, but returns count
2043 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
2046 wchar2ascii(char *abuf
, ushort
*wbuf
, ushort wbuflen
, ulong abuflen
)
2054 /* wbuflen is in bytes */
2055 wbuflen
/= sizeof(ushort
);
2057 for (i
= 0; i
< wbuflen
; ++i
) {
2060 *abuf
++ = (char) *wbuf
++;
2067 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
2069 #ifdef BCM_OBJECT_TRACE
2071 #define BCM_OBJECT_MERGE_SAME_OBJ 0
2073 /* some place may add / remove the object to trace list for Linux: */
2074 /* add: osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */
2075 /* remove: osl_pktfree dev_kfree_skb netif_rx */
2077 #define BCM_OBJDBG_COUNT (1024 * 100)
2078 static spinlock_t dbgobj_lock
;
2079 #define BCM_OBJDBG_LOCK_INIT() spin_lock_init(&dbgobj_lock)
2080 #define BCM_OBJDBG_LOCK_DESTROY()
2081 #define BCM_OBJDBG_LOCK spin_lock_irqsave
2082 #define BCM_OBJDBG_UNLOCK spin_unlock_irqrestore
2084 #define BCM_OBJDBG_ADDTOHEAD 0
2085 #define BCM_OBJDBG_ADDTOTAIL 1
2087 #define BCM_OBJDBG_CALLER_LEN 32
2089 struct bcm_dbgobj
*prior
;
2090 struct bcm_dbgobj
*next
;
2096 char caller
[BCM_OBJDBG_CALLER_LEN
];
2099 static struct bcm_dbgobj
*dbgobj_freehead
= NULL
;
2100 static struct bcm_dbgobj
*dbgobj_freetail
= NULL
;
2101 static struct bcm_dbgobj
*dbgobj_objhead
= NULL
;
2102 static struct bcm_dbgobj
*dbgobj_objtail
= NULL
;
2104 static uint32 dbgobj_sn
= 0;
2105 static int dbgobj_count
= 0;
2106 static struct bcm_dbgobj bcm_dbg_objs
[BCM_OBJDBG_COUNT
];
2109 bcm_object_trace_init(void)
2112 BCM_OBJDBG_LOCK_INIT();
2113 memset(&bcm_dbg_objs
, 0x00, sizeof(struct bcm_dbgobj
) * BCM_OBJDBG_COUNT
);
2114 dbgobj_freehead
= &bcm_dbg_objs
[0];
2115 dbgobj_freetail
= &bcm_dbg_objs
[BCM_OBJDBG_COUNT
- 1];
2117 for (i
= 0; i
< BCM_OBJDBG_COUNT
; ++i
) {
2118 bcm_dbg_objs
[i
].next
= (i
== (BCM_OBJDBG_COUNT
- 1)) ?
2119 dbgobj_freehead
: &bcm_dbg_objs
[i
+ 1];
2120 bcm_dbg_objs
[i
].prior
= (i
== 0) ?
2121 dbgobj_freetail
: &bcm_dbg_objs
[i
- 1];
2126 bcm_object_trace_deinit(void)
2128 if (dbgobj_objhead
|| dbgobj_objtail
) {
2129 printf("%s: not all objects are released\n", __FUNCTION__
);
2132 BCM_OBJDBG_LOCK_DESTROY();
2136 bcm_object_rm_list(struct bcm_dbgobj
**head
, struct bcm_dbgobj
**tail
,
2137 struct bcm_dbgobj
*dbgobj
)
2139 if ((dbgobj
== *head
) && (dbgobj
== *tail
)) {
2142 } else if (dbgobj
== *head
) {
2143 *head
= (*head
)->next
;
2144 } else if (dbgobj
== *tail
) {
2145 *tail
= (*tail
)->prior
;
2147 dbgobj
->next
->prior
= dbgobj
->prior
;
2148 dbgobj
->prior
->next
= dbgobj
->next
;
2152 bcm_object_add_list(struct bcm_dbgobj
**head
, struct bcm_dbgobj
**tail
,
2153 struct bcm_dbgobj
*dbgobj
, int addtotail
)
2155 if (!(*head
) && !(*tail
)) {
2158 dbgobj
->next
= dbgobj
;
2159 dbgobj
->prior
= dbgobj
;
2160 } else if ((*head
) && (*tail
)) {
2161 (*tail
)->next
= dbgobj
;
2162 (*head
)->prior
= dbgobj
;
2163 dbgobj
->next
= *head
;
2164 dbgobj
->prior
= *tail
;
2165 if (addtotail
== BCM_OBJDBG_ADDTOTAIL
)
2170 ASSERT(0); /* can't be this case */
2175 bcm_object_movetoend(struct bcm_dbgobj
**head
, struct bcm_dbgobj
**tail
,
2176 struct bcm_dbgobj
*dbgobj
, int movetotail
)
2178 if ((*head
) && (*tail
)) {
2179 if (movetotail
== BCM_OBJDBG_ADDTOTAIL
) {
2180 if (dbgobj
!= (*tail
)) {
2181 bcm_object_rm_list(head
, tail
, dbgobj
);
2182 bcm_object_add_list(head
, tail
, dbgobj
, movetotail
);
2185 if (dbgobj
!= (*head
)) {
2186 bcm_object_rm_list(head
, tail
, dbgobj
);
2187 bcm_object_add_list(head
, tail
, dbgobj
, movetotail
);
2191 ASSERT(0); /* can't be this case */
2196 bcm_object_trace_opr(void *obj
, uint32 opt
, const char *caller
, int line
)
2198 struct bcm_dbgobj
*dbgobj
;
2199 unsigned long flags
;
2201 BCM_REFERENCE(flags
);
2202 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
2204 if (opt
== BCM_OBJDBG_ADD_PKT
||
2205 opt
== BCM_OBJDBG_ADD
) {
2206 dbgobj
= dbgobj_objtail
;
2208 if (dbgobj
->obj
== obj
) {
2209 printf("%s: obj %p allocated from %s(%d),"
2210 " allocate again from %s(%d)\n",
2211 __FUNCTION__
, dbgobj
->obj
,
2212 dbgobj
->caller
, dbgobj
->line
,
2217 dbgobj
= dbgobj
->prior
;
2218 if (dbgobj
== dbgobj_objtail
)
2222 #if BCM_OBJECT_MERGE_SAME_OBJ
2223 dbgobj
= dbgobj_freetail
;
2225 if (dbgobj
->obj
== obj
) {
2226 goto FREED_ENTRY_FOUND
;
2228 dbgobj
= dbgobj
->prior
;
2229 if (dbgobj
== dbgobj_freetail
)
2232 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
2234 dbgobj
= dbgobj_freehead
;
2235 #if BCM_OBJECT_MERGE_SAME_OBJ
2237 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
2239 printf("%s: already got %d objects ?????????????????????\n",
2240 __FUNCTION__
, BCM_OBJDBG_COUNT
);
2245 bcm_object_rm_list(&dbgobj_freehead
, &dbgobj_freetail
, dbgobj
);
2247 strncpy(dbgobj
->caller
, caller
, BCM_OBJDBG_CALLER_LEN
);
2248 dbgobj
->caller
[BCM_OBJDBG_CALLER_LEN
-1] = '\0';
2249 dbgobj
->line
= line
;
2251 if (opt
== BCM_OBJDBG_ADD_PKT
) {
2252 dbgobj
->obj_sn
= dbgobj_sn
++;
2253 dbgobj
->obj_state
= 0;
2254 /* first 4 bytes is pkt sn */
2255 if (((unsigned long)PKTTAG(obj
)) & 0x3)
2256 printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj
));
2257 *(uint32
*)PKTTAG(obj
) = dbgobj
->obj_sn
;
2259 bcm_object_add_list(&dbgobj_objhead
, &dbgobj_objtail
, dbgobj
,
2260 BCM_OBJDBG_ADDTOTAIL
);
2264 } else if (opt
== BCM_OBJDBG_REMOVE
) {
2265 dbgobj
= dbgobj_objtail
;
2267 if (dbgobj
->obj
== obj
) {
2269 printf("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n",
2270 __FUNCTION__
, obj
, dbgobj
->flag
, caller
, line
);
2272 bcm_object_rm_list(&dbgobj_objhead
, &dbgobj_objtail
, dbgobj
);
2273 memset(dbgobj
->caller
, 0x00, BCM_OBJDBG_CALLER_LEN
);
2274 strncpy(dbgobj
->caller
, caller
, BCM_OBJDBG_CALLER_LEN
);
2275 dbgobj
->caller
[BCM_OBJDBG_CALLER_LEN
-1] = '\0';
2276 dbgobj
->line
= line
;
2277 bcm_object_add_list(&dbgobj_freehead
, &dbgobj_freetail
, dbgobj
,
2278 BCM_OBJDBG_ADDTOTAIL
);
2282 dbgobj
= dbgobj
->prior
;
2283 if (dbgobj
== dbgobj_objtail
)
2287 dbgobj
= dbgobj_freetail
;
2288 while (dbgobj
&& dbgobj
->obj
) {
2289 if (dbgobj
->obj
== obj
) {
2290 printf("%s: obj %p already freed from from %s(%d),"
2291 " try free again from %s(%d)\n",
2293 dbgobj
->caller
, dbgobj
->line
,
2295 //ASSERT(0); /* release same obj more than one time? */
2298 dbgobj
= dbgobj
->prior
;
2299 if (dbgobj
== dbgobj_freetail
)
2303 printf("%s: ################### release none-existing obj %p from %s(%d)\n",
2304 __FUNCTION__
, obj
, caller
, line
);
2305 //ASSERT(0); /* release same obj more than one time? */
2310 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
2315 bcm_object_trace_upd(void *obj
, void *obj_new
)
2317 struct bcm_dbgobj
*dbgobj
;
2318 unsigned long flags
;
2320 BCM_REFERENCE(flags
);
2321 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
2323 dbgobj
= dbgobj_objtail
;
2325 if (dbgobj
->obj
== obj
) {
2326 dbgobj
->obj
= obj_new
;
2327 if (dbgobj
!= dbgobj_objtail
) {
2328 bcm_object_movetoend(&dbgobj_objhead
, &dbgobj_objtail
,
2329 dbgobj
, BCM_OBJDBG_ADDTOTAIL
);
2333 dbgobj
= dbgobj
->prior
;
2334 if (dbgobj
== dbgobj_objtail
)
2339 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
2344 bcm_object_trace_chk(void *obj
, uint32 chksn
, uint32 sn
,
2345 const char *caller
, int line
)
2347 struct bcm_dbgobj
*dbgobj
;
2348 unsigned long flags
;
2350 BCM_REFERENCE(flags
);
2351 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
2353 dbgobj
= dbgobj_objtail
;
2355 if ((dbgobj
->obj
== obj
) &&
2356 ((!chksn
) || (dbgobj
->obj_sn
== sn
))) {
2357 if (dbgobj
!= dbgobj_objtail
) {
2358 bcm_object_movetoend(&dbgobj_objhead
, &dbgobj_objtail
,
2359 dbgobj
, BCM_OBJDBG_ADDTOTAIL
);
2363 dbgobj
= dbgobj
->prior
;
2364 if (dbgobj
== dbgobj_objtail
)
2368 dbgobj
= dbgobj_freetail
;
2370 if ((dbgobj
->obj
== obj
) &&
2371 ((!chksn
) || (dbgobj
->obj_sn
== sn
))) {
2372 printf("%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n",
2373 __FUNCTION__
, caller
, line
,
2374 dbgobj
->obj
, dbgobj
->obj_sn
, dbgobj
->obj_state
,
2375 dbgobj
->caller
, dbgobj
->line
);
2378 else if (dbgobj
->obj
== NULL
) {
2381 dbgobj
= dbgobj
->prior
;
2382 if (dbgobj
== dbgobj_freetail
)
2386 printf("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n",
2387 __FUNCTION__
, obj
, caller
, line
, chksn
? "yes" : "no", sn
);
2388 dbgobj
= dbgobj_objtail
;
2390 printf("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n",
2391 __FUNCTION__
, caller
, line
,
2392 dbgobj
->obj
, dbgobj
->obj_sn
, dbgobj
->caller
, dbgobj
->line
);
2393 dbgobj
= dbgobj
->prior
;
2394 if (dbgobj
== dbgobj_objtail
)
2399 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
2404 bcm_object_feature_set(void *obj
, uint32 type
, uint32 value
)
2406 struct bcm_dbgobj
*dbgobj
;
2407 unsigned long flags
;
2409 BCM_REFERENCE(flags
);
2410 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
2412 dbgobj
= dbgobj_objtail
;
2414 if (dbgobj
->obj
== obj
) {
2415 if (type
== BCM_OBJECT_FEATURE_FLAG
) {
2416 if (value
& BCM_OBJECT_FEATURE_CLEAR
)
2417 dbgobj
->flag
&= ~(value
);
2419 dbgobj
->flag
|= (value
);
2420 } else if (type
== BCM_OBJECT_FEATURE_PKT_STATE
) {
2421 dbgobj
->obj_state
= value
;
2423 if (dbgobj
!= dbgobj_objtail
) {
2424 bcm_object_movetoend(&dbgobj_objhead
, &dbgobj_objtail
,
2425 dbgobj
, BCM_OBJDBG_ADDTOTAIL
);
2429 dbgobj
= dbgobj
->prior
;
2430 if (dbgobj
== dbgobj_objtail
)
2434 printf("%s: obj %p not found in active list\n", __FUNCTION__
, obj
);
2438 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
2443 bcm_object_feature_get(void *obj
, uint32 type
, uint32 value
)
2446 struct bcm_dbgobj
*dbgobj
;
2447 unsigned long flags
;
2449 BCM_REFERENCE(flags
);
2450 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
2452 dbgobj
= dbgobj_objtail
;
2454 if (dbgobj
->obj
== obj
) {
2455 if (type
== BCM_OBJECT_FEATURE_FLAG
) {
2456 rtn
= (dbgobj
->flag
& value
) & (~BCM_OBJECT_FEATURE_CLEAR
);
2458 if (dbgobj
!= dbgobj_objtail
) {
2459 bcm_object_movetoend(&dbgobj_objhead
, &dbgobj_objtail
,
2460 dbgobj
, BCM_OBJDBG_ADDTOTAIL
);
2464 dbgobj
= dbgobj
->prior
;
2465 if (dbgobj
== dbgobj_objtail
)
2469 printf("%s: obj %p not found in active list\n", __FUNCTION__
, obj
);
2473 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
2477 #endif /* BCM_OBJECT_TRACE */
2480 bcm_write_tlv(int type
, const void *data
, int datalen
, uint8
*dst
)
2482 uint8
*new_dst
= dst
;
2483 bcm_tlv_t
*dst_tlv
= (bcm_tlv_t
*)dst
;
2485 /* dst buffer should always be valid */
2488 /* data len must be within valid range */
2489 ASSERT((datalen
>= 0) && (datalen
<= BCM_TLV_MAX_DATA_SIZE
));
2491 /* source data buffer pointer should be valid, unless datalen is 0
2492 * meaning no data with this TLV
2494 ASSERT((data
!= NULL
) || (datalen
== 0));
2496 /* only do work if the inputs are valid
2497 * - must have a dst to write to AND
2498 * - datalen must be within range AND
2499 * - the source data pointer must be non-NULL if datalen is non-zero
2500 * (this last condition detects datalen > 0 with a NULL data pointer)
2502 if ((dst
!= NULL
) &&
2503 ((datalen
>= 0) && (datalen
<= BCM_TLV_MAX_DATA_SIZE
)) &&
2504 ((data
!= NULL
) || (datalen
== 0))) {
2506 /* write type, len fields */
2507 dst_tlv
->id
= (uint8
)type
;
2508 dst_tlv
->len
= (uint8
)datalen
;
2510 /* if data is present, copy to the output buffer and update
2511 * pointer to output buffer
2515 memcpy(dst_tlv
->data
, data
, datalen
);
2518 /* update the output destination poitner to point past
2521 new_dst
= dst
+ BCM_TLV_HDR_SIZE
+ datalen
;
2528 bcm_write_tlv_ext(uint8 type
, uint8 ext
, const void *data
, uint8 datalen
, uint8
*dst
)
2530 uint8
*new_dst
= dst
;
2531 bcm_tlv_ext_t
*dst_tlv
= (bcm_tlv_ext_t
*)dst
;
2533 /* dst buffer should always be valid */
2536 /* data len must be within valid range */
2537 ASSERT(datalen
<= BCM_TLV_EXT_MAX_DATA_SIZE
);
2539 /* source data buffer pointer should be valid, unless datalen is 0
2540 * meaning no data with this TLV
2542 ASSERT((data
!= NULL
) || (datalen
== 0));
2544 /* only do work if the inputs are valid
2545 * - must have a dst to write to AND
2546 * - datalen must be within range AND
2547 * - the source data pointer must be non-NULL if datalen is non-zero
2548 * (this last condition detects datalen > 0 with a NULL data pointer)
2550 if ((dst
!= NULL
) &&
2551 (datalen
<= BCM_TLV_EXT_MAX_DATA_SIZE
) &&
2552 ((data
!= NULL
) || (datalen
== 0))) {
2554 /* write type, len fields */
2555 dst_tlv
->id
= (uint8
)type
;
2557 dst_tlv
->len
= 1 + (uint8
)datalen
;
2559 /* if data is present, copy to the output buffer and update
2560 * pointer to output buffer
2563 memcpy(dst_tlv
->data
, data
, datalen
);
2566 /* update the output destination poitner to point past
2569 new_dst
= dst
+ BCM_TLV_EXT_HDR_SIZE
+ datalen
;
2576 bcm_write_tlv_safe(int type
, const void *data
, int datalen
, uint8
*dst
, int dst_maxlen
)
2578 uint8
*new_dst
= dst
;
2580 if ((datalen
>= 0) && (datalen
<= BCM_TLV_MAX_DATA_SIZE
)) {
2582 /* if len + tlv hdr len is more than destlen, don't do anything
2583 * just return the buffer untouched
2585 if ((int)(datalen
+ BCM_TLV_HDR_SIZE
) <= dst_maxlen
) {
2587 new_dst
= bcm_write_tlv(type
, data
, datalen
, dst
);
2595 bcm_copy_tlv(const void *src
, uint8
*dst
)
2597 uint8
*new_dst
= dst
;
2598 const bcm_tlv_t
*src_tlv
= (const bcm_tlv_t
*)src
;
2604 totlen
= BCM_TLV_HDR_SIZE
+ src_tlv
->len
;
2605 memcpy(dst
, src_tlv
, totlen
);
2606 new_dst
= dst
+ totlen
;
2612 uint8
*bcm_copy_tlv_safe(const void *src
, uint8
*dst
, int dst_maxlen
)
2614 uint8
*new_dst
= dst
;
2615 const bcm_tlv_t
*src_tlv
= (const bcm_tlv_t
*)src
;
2619 if (bcm_valid_tlv(src_tlv
, dst_maxlen
)) {
2620 new_dst
= bcm_copy_tlv(src
, dst
);
2627 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
2628 /*******************************************************************************
2631 * Computes a crc8 over the input data using the polynomial:
2633 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
2635 * The caller provides the initial value (either CRC8_INIT_VALUE
2636 * or the previous returned value) to allow for processing of
2637 * discontiguous blocks of data. When generating the CRC the
2638 * caller is responsible for complementing the final return value
2639 * and inserting it into the byte stream. When checking, a final
2640 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
2642 * Reference: Dallas Semiconductor Application Note 27
2643 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2644 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2645 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2647 * ****************************************************************************
2650 static const uint8 crc8_table
[256] = {
2651 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
2652 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
2653 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
2654 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
2655 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
2656 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
2657 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
2658 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
2659 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
2660 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
2661 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
2662 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
2663 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
2664 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
2665 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
2666 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
2667 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
2668 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
2669 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
2670 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
2671 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
2672 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
2673 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
2674 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
2675 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
2676 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
2677 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
2678 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
2679 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
2680 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
2681 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
2682 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
2685 #define CRC_INNER_LOOP(n, c, x) \
2686 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
2690 const uint8
*pdata
, /* pointer to array of data to process */
2691 uint nbytes
, /* number of input data bytes to process */
2692 uint8 crc
/* either CRC8_INIT_VALUE or previous return value */
2695 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
2696 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
2698 while (nbytes
-- > 0)
2699 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
2704 /*******************************************************************************
2707 * Computes a crc16 over the input data using the polynomial:
2709 * x^16 + x^12 +x^5 + 1
2711 * The caller provides the initial value (either CRC16_INIT_VALUE
2712 * or the previous returned value) to allow for processing of
2713 * discontiguous blocks of data. When generating the CRC the
2714 * caller is responsible for complementing the final return value
2715 * and inserting it into the byte stream. When checking, a final
2716 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
2718 * Reference: Dallas Semiconductor Application Note 27
2719 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2720 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2721 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2723 * ****************************************************************************
2726 static const uint16 crc16_table
[256] = {
2727 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
2728 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
2729 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
2730 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
2731 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
2732 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
2733 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
2734 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
2735 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
2736 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
2737 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
2738 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
2739 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
2740 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
2741 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
2742 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
2743 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
2744 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
2745 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
2746 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
2747 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
2748 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
2749 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
2750 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
2751 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
2752 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
2753 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
2754 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
2755 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
2756 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
2757 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
2758 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
2763 const uint8
*pdata
, /* pointer to array of data to process */
2764 uint nbytes
, /* number of input data bytes to process */
2765 uint16 crc
/* either CRC16_INIT_VALUE or previous return value */
2768 while (nbytes
-- > 0)
2769 CRC_INNER_LOOP(16, crc
, *pdata
++);
2773 static const uint32 crc32_table
[256] = {
2774 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
2775 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
2776 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
2777 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
2778 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
2779 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
2780 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
2781 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
2782 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
2783 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
2784 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
2785 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
2786 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
2787 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
2788 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
2789 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
2790 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
2791 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
2792 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
2793 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
2794 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
2795 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
2796 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
2797 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
2798 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
2799 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
2800 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
2801 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
2802 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
2803 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
2804 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
2805 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
2806 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
2807 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
2808 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
2809 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
2810 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
2811 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
2812 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
2813 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
2814 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
2815 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
2816 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
2817 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
2818 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
2819 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
2820 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
2821 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
2822 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
2823 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
2824 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
2825 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
2826 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
2827 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
2828 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
2829 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
2830 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
2831 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
2832 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
2833 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
2834 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
2835 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
2836 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
2837 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
2841 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
2842 * accumulating over multiple pieces.
2845 hndcrc32(const uint8
*pdata
, uint nbytes
, uint32 crc
)
2848 pend
= pdata
+ nbytes
;
2849 while (pdata
< pend
)
2850 CRC_INNER_LOOP(32, crc
, *pdata
++);
2856 #define CLEN 1499 /* CRC Length */
2857 #define CBUFSIZ (CLEN+4)
2858 #define CNBUFS 5 /* # of bufs */
2867 uint32 crc32tv
[CNBUFS
] =
2868 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
2870 ASSERT((buf
= MALLOC(CBUFSIZ
*CNBUFS
)) != NULL
);
2872 /* step through all possible alignments */
2873 for (l
= 0; l
<= 4; l
++) {
2874 for (j
= 0; j
< CNBUFS
; j
++) {
2876 for (k
= 0; k
< len
[j
]; k
++)
2877 *(buf
+ j
*CBUFSIZ
+ (k
+l
)) = (j
+k
) & 0xff;
2880 for (j
= 0; j
< CNBUFS
; j
++) {
2881 crcr
= crc32(buf
+ j
*CBUFSIZ
+ l
, len
[j
], CRC32_INIT_VALUE
);
2882 ASSERT(crcr
== crc32tv
[j
]);
2886 MFREE(buf
, CBUFSIZ
*CNBUFS
);
2892 * Advance from the current 1-byte tag/1-byte length/variable-length value
2893 * triple, to the next, returning a pointer to the next.
2894 * If the current or next TLV is invalid (does not fit in given buffer length),
2896 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
2897 * by the TLV parameter's length if it is valid.
2900 bcm_next_tlv(const bcm_tlv_t
*elt
, uint
*buflen
)
2904 /* validate current elt */
2905 if (!bcm_valid_tlv(elt
, *buflen
)) {
2909 /* advance to next elt */
2911 elt
= (const bcm_tlv_t
*)(elt
->data
+ len
);
2912 *buflen
-= (TLV_HDR_LEN
+ len
);
2914 /* validate next elt */
2915 if (!bcm_valid_tlv(elt
, *buflen
)) {
2919 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2920 return (bcm_tlv_t
*)(elt
);
2921 GCC_DIAGNOSTIC_POP();
2925 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2926 * triples, returning a pointer to the substring whose first element
2930 bcm_parse_tlvs(const void *buf
, uint buflen
, uint key
)
2932 const bcm_tlv_t
*elt
;
2935 if ((elt
= (const bcm_tlv_t
*)buf
) == NULL
) {
2938 totlen
= (int)buflen
;
2940 /* find tagged parameter */
2941 while (totlen
>= TLV_HDR_LEN
) {
2942 uint len
= elt
->len
;
2944 /* validate remaining totlen */
2945 if ((elt
->id
== key
) && (totlen
>= (int)(len
+ TLV_HDR_LEN
))) {
2946 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2947 return (bcm_tlv_t
*)(elt
);
2948 GCC_DIAGNOSTIC_POP();
2951 elt
= (const bcm_tlv_t
*)((const uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2952 totlen
-= (len
+ TLV_HDR_LEN
);
2959 bcm_parse_tlvs_dot11(const void *buf
, int buflen
, uint key
, bool id_ext
)
2965 ideally, we don't want to do that, but returning a const pointer
2966 from these parse function spreads casting everywhere in the code
2968 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2969 elt
= (bcm_tlv_t
*)buf
;
2970 GCC_DIAGNOSTIC_POP();
2974 /* find tagged parameter */
2975 while (totlen
>= TLV_HDR_LEN
) {
2979 /* validate remaining totlen */
2980 if (totlen
< (int)(len
+ TLV_HDR_LEN
))
2984 if (!DOT11_MNG_IE_ID_EXT_MATCH(elt
, key
))
2986 } else if (elt
->id
!= key
) {
2990 return (bcm_tlv_t
*)(elt
); /* a match */
2993 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2994 totlen
-= (len
+ TLV_HDR_LEN
);
3001 * Traverse a string of 1-byte tag/1-byte length/variable-length value
3002 * triples, returning a pointer to the substring whose first element
3004 * return NULL if not found or length field < min_varlen
3007 bcm_parse_tlvs_min_bodylen(const void *buf
, int buflen
, uint key
, int min_bodylen
)
3010 ret
= bcm_parse_tlvs(buf
, buflen
, key
);
3011 if (ret
== NULL
|| ret
->len
< min_bodylen
) {
3018 * Traverse a string of 1-byte tag/1-byte length/variable-length value
3019 * triples, returning a pointer to the substring whose first element
3020 * matches tag. Stop parsing when we see an element whose ID is greater
3021 * than the target key.
3024 bcm_parse_ordered_tlvs(const void *buf
, int buflen
, uint key
)
3026 const bcm_tlv_t
*elt
;
3029 elt
= (const bcm_tlv_t
*)buf
;
3032 /* find tagged parameter */
3033 while (totlen
>= TLV_HDR_LEN
) {
3037 /* Punt if we start seeing IDs > than target key */
3042 /* validate remaining totlen */
3043 if ((id
== key
) && (totlen
>= (int)(len
+ TLV_HDR_LEN
))) {
3047 elt
= (const bcm_tlv_t
*)((const uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
3048 totlen
-= (len
+ TLV_HDR_LEN
);
3052 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
3054 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
3057 bcm_format_field(const bcm_bit_desc_ex_t
*bd
, uint32 flags
, char* buf
, int len
)
3063 if (len
< 2 || !buf
)
3068 for (i
= 0; (name
= bd
->bitfield
[i
].name
) != NULL
; i
++) {
3069 bit
= bd
->bitfield
[i
].bit
;
3070 if ((flags
& mask
) == bit
) {
3071 if (len
> (int)strlen(name
)) {
3072 slen
= strlen(name
);
3073 strncpy(buf
, name
, slen
+1);
3082 bcm_format_flags(const bcm_bit_desc_t
*bd
, uint32 flags
, char* buf
, int len
)
3087 int slen
= 0, nlen
= 0;
3091 if (len
< 2 || !buf
)
3096 for (i
= 0; flags
!= 0; i
++) {
3099 if (bit
== 0 && flags
!= 0) {
3100 /* print any unnamed bits */
3101 snprintf(hexstr
, 16, "0x%X", flags
);
3103 flags
= 0; /* exit loop */
3104 } else if ((flags
& bit
) == 0)
3107 nlen
= strlen(name
);
3109 /* count btwn flag space */
3112 /* need NULL char as well */
3115 /* copy NULL char but don't count it */
3116 strncpy(p
, name
, nlen
+ 1);
3118 /* copy btwn flag space and NULL char */
3120 p
+= snprintf(p
, 2, " ");
3123 /* indicate the str was too short */
3125 p
+= snprintf(p
, 2, ">");
3128 return (int)(p
- buf
);
3131 /* print out whcih bits in octet array 'addr' are set. bcm_bit_desc_t:bit is a bit offset. */
3133 bcm_format_octets(const bcm_bit_desc_t
*bd
, uint bdsz
,
3134 const uint8
*addr
, uint size
, char *buf
, int len
)
3138 int slen
= 0, nlen
= 0;
3143 BCM_REFERENCE(size
);
3145 if (len
< 2 || !buf
)
3150 for (i
= 0; i
< bdsz
; i
++) {
3153 if (isset(addr
, bit
)) {
3154 nlen
= strlen(name
);
3156 /* need SPACE - for simplicity */
3158 /* need NULL as well */
3159 if (len
< slen
+ 1) {
3163 memcpy(p
, name
, nlen
);
3177 return (int)(p
- buf
);
3181 /* print bytes formatted as hex to a string. return the resulting string length */
3183 bcm_format_hex(char *str
, const void *bytes
, int len
)
3187 const uint8
*src
= (const uint8
*)bytes
;
3189 for (i
= 0; i
< len
; i
++) {
3190 p
+= snprintf(p
, 3, "%02X", *src
);
3193 return (int)(p
- str
);
3196 /* pretty hex print a contiguous buffer */
3198 prhex(const char *msg
, const uchar
*buf
, uint nbytes
)
3201 int len
= sizeof(line
);
3205 if (msg
&& (msg
[0] != '\0'))
3206 printf("%s:\n", msg
);
3209 for (i
= 0; i
< nbytes
; i
++) {
3211 nchar
= snprintf(p
, len
, " %04x: ", i
); /* line prefix */
3216 nchar
= snprintf(p
, len
, "%02x ", buf
[i
]);
3222 printf("%s\n", line
); /* flush line */
3228 /* flush last partial line */
3230 printf("%s\n", line
);
3233 static const char *crypto_algo_names
[] = {
3269 bcm_crypto_algo_name(uint algo
)
3271 return (algo
< ARRAYSIZE(crypto_algo_names
)) ? crypto_algo_names
[algo
] : "ERR";
3275 bcm_chipname(uint chipid
, char *buf
, uint len
)
3279 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
3280 snprintf(buf
, len
, fmt
, chipid
);
3284 /* Produce a human-readable string for boardrev */
3286 bcm_brev_str(uint32 brev
, char *buf
)
3289 snprintf(buf
, 8, "%d.%d", (brev
& 0xf0) >> 4, brev
& 0xf);
3291 snprintf(buf
, 8, "%c%03x", ((brev
& 0xf000) == 0x1000) ? 'P' : 'A', brev
& 0xfff);
3296 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
3298 /* dump large strings to console */
3305 len
= (uint
)strlen(buf
);
3307 max_len
= BUFSIZE_TODUMP_ATONCE
;
3309 while (len
> max_len
) {
3311 buf
[max_len
] = '\0';
3318 /* print the remaining string */
3319 printf("%s\n", buf
);
3323 /* routine to dump fields in a fileddesc structure */
3325 bcmdumpfields(bcmutl_rdreg_rtn read_rtn
, void *arg0
, uint arg1
, struct fielddesc
*fielddesc_array
,
3326 char *buf
, uint32 bufsize
)
3330 struct fielddesc
*cur_ptr
;
3333 cur_ptr
= fielddesc_array
;
3335 while (bufsize
> 1) {
3336 if (cur_ptr
->nameandfmt
== NULL
)
3338 len
= snprintf(buf
, bufsize
, cur_ptr
->nameandfmt
,
3339 read_rtn(arg0
, arg1
, cur_ptr
->offset
));
3340 /* check for snprintf overflow or error */
3341 if (len
< 0 || (uint32
)len
>= bufsize
)
3352 bcm_mkiovar(const char *name
, const char *data
, uint datalen
, char *buf
, uint buflen
)
3356 len
= (uint
)strlen(name
) + 1;
3358 if ((len
+ datalen
) > buflen
)
3361 strncpy(buf
, name
, buflen
);
3363 /* append data onto the end of the name string */
3364 if (data
&& datalen
!= 0) {
3365 memcpy(&buf
[len
], data
, datalen
);
3372 /* Quarter dBm units to mW
3373 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
3374 * Table is offset so the last entry is largest mW value that fits in
3378 #define QDBM_OFFSET 153 /* Offset for first entry */
3379 #define QDBM_TABLE_LEN 40 /* Table size */
3381 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
3382 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
3384 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
3386 /* Largest mW value that will round down to the last table entry,
3387 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
3388 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
3390 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
3392 static const uint16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
3393 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
3394 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
3395 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
3396 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
3397 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
3398 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
3402 bcm_qdbm_to_mw(uint8 qdbm
)
3405 int idx
= qdbm
- QDBM_OFFSET
;
3407 if (idx
>= QDBM_TABLE_LEN
) {
3408 /* clamp to max uint16 mW value */
3412 /* scale the qdBm index up to the range of the table 0-40
3413 * where an offset of 40 qdBm equals a factor of 10 mW.
3420 /* return the mW value scaled down to the correct factor of 10,
3421 * adding in factor/2 to get proper rounding.
3423 return ((nqdBm_to_mW_map
[idx
] + factor
/2) / factor
);
3427 bcm_mw_to_qdbm(uint16 mw
)
3434 /* handle boundary case */
3438 offset
= QDBM_OFFSET
;
3440 /* move mw into the range of the table */
3441 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
3446 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
-1; qdbm
++) {
3447 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+1] -
3448 nqdBm_to_mW_map
[qdbm
])/2;
3449 if (mw_uint
< boundary
) break;
3452 qdbm
+= (uint8
)offset
;
3458 bcm_bitcount(uint8
*bitmap
, uint length
)
3460 uint bitcount
= 0, i
;
3462 for (i
= 0; i
< length
; i
++) {
3473 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
3474 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
3475 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
3476 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
3480 process_nvram_vars(char *varbuf
, unsigned int len
)
3485 unsigned int buf_len
, n
;
3486 unsigned int pad
= 0;
3490 findNewline
= FALSE
;
3493 for (n
= 0; n
< len
; n
++) {
3494 if (varbuf
[n
] == '\r')
3496 if (findNewline
&& varbuf
[n
] != '\n')
3498 findNewline
= FALSE
;
3499 if (varbuf
[n
] == '#') {
3503 if (varbuf
[n
] == '\n') {
3513 buf_len
= (unsigned int)(dp
- varbuf
);
3515 pad
= 4 - buf_len
% 4;
3516 if (pad
&& (buf_len
+ pad
<= len
)) {
3521 while (dp
< varbuf
+ n
)
3527 #ifndef setbit /* As in the header file */
3528 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
3529 /* Set bit in byte array. */
3531 setbit(void *array
, uint bit
)
3533 ((uint8
*)array
)[bit
/ NBBY
] |= 1 << (bit
% NBBY
);
3536 /* Clear bit in byte array. */
3538 clrbit(void *array
, uint bit
)
3540 ((uint8
*)array
)[bit
/ NBBY
] &= ~(1 << (bit
% NBBY
));
3543 /* Test if bit is set in byte array. */
3545 isset(const void *array
, uint bit
)
3547 return (((const uint8
*)array
)[bit
/ NBBY
] & (1 << (bit
% NBBY
)));
3550 /* Test if bit is clear in byte array. */
3552 isclr(const void *array
, uint bit
)
3554 return ((((const uint8
*)array
)[bit
/ NBBY
] & (1 << (bit
% NBBY
))) == 0);
3556 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
3560 set_bitrange(void *array
, uint start
, uint end
, uint maxbit
)
3562 uint startbyte
= start
/NBBY
;
3563 uint endbyte
= end
/NBBY
;
3564 uint i
, startbytelastbit
, endbytestartbit
;
3567 if (endbyte
- startbyte
> 1)
3569 startbytelastbit
= (startbyte
+1)*NBBY
- 1;
3570 endbytestartbit
= endbyte
*NBBY
;
3571 for (i
= startbyte
+1; i
< endbyte
; i
++)
3572 ((uint8
*)array
)[i
] = 0xFF;
3573 for (i
= start
; i
<= startbytelastbit
; i
++)
3575 for (i
= endbytestartbit
; i
<= end
; i
++)
3578 for (i
= start
; i
<= end
; i
++)
3583 set_bitrange(array
, start
, maxbit
, maxbit
);
3584 set_bitrange(array
, 0, end
, maxbit
);
3589 bcm_bitprint32(const uint32 u32arg
)
3592 for (i
= NBITS(uint32
) - 1; i
>= 0; i
--) {
3593 if (isbitset(u32arg
, i
)) {
3599 if ((i
% NBBY
) == 0) printf(" ");
3604 /* calculate checksum for ip header, tcp / udp header / data */
3606 bcm_ip_cksum(uint8
*buf
, uint32 len
, uint32 sum
)
3609 sum
+= (buf
[0] << 8) | buf
[1];
3619 sum
= (sum
& 0xffff) + (sum
>> 16);
3622 return ((uint16
)~sum
);
3626 BCMRAMFN(valid_bcmerror
)(int e
)
3628 return ((e
<= 0) && (e
>= BCME_LAST
));
3631 #ifdef DEBUG_COUNTER
3632 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
3633 void counter_printlog(counter_tbl_t
*ctr_tbl
)
3637 if (!ctr_tbl
->enabled
)
3640 now
= OSL_SYSUPTIME();
3642 if (now
- ctr_tbl
->prev_log_print
> ctr_tbl
->log_print_interval
) {
3644 printf("counter_print(%s %d):", ctr_tbl
->name
, now
- ctr_tbl
->prev_log_print
);
3646 for (i
= 0; i
< ctr_tbl
->needed_cnt
; i
++) {
3647 printf(" %u", ctr_tbl
->cnt
[i
]);
3651 ctr_tbl
->prev_log_print
= now
;
3652 bzero(ctr_tbl
->cnt
, CNTR_TBL_MAX
* sizeof(uint
));
3656 /* OSL_SYSUPTIME is not supported so no way to get time */
3657 #define counter_printlog(a) do {} while (0)
3658 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
3659 #endif /* DEBUG_COUNTER */
3661 /* calculate partial checksum */
3663 ip_cksum_partial(uint32 sum
, uint8
*val8
, uint32 count
)
3666 uint16
*val16
= (uint16
*)val8
;
3668 ASSERT(val8
!= NULL
);
3669 /* partial chksum calculated on 16-bit values */
3670 ASSERT((count
% 2) == 0);
3674 for (i
= 0; i
< count
; i
++) {
3680 /* calculate IP checksum */
3682 ip_cksum(uint32 sum
, uint8
*val8
, uint32 count
)
3684 uint16
*val16
= (uint16
*)val8
;
3686 ASSERT(val8
!= NULL
);
3692 /* add left-over byte, if any */
3694 sum
+= (*(uint8
*)val16
);
3697 /* fold 32-bit sum to 16 bits */
3698 sum
= (sum
>> 16) + (sum
& 0xffff);
3700 return ((uint16
)~sum
);
3703 /* calculate IPv4 header checksum
3704 * - input ip points to IP header in network order
3705 * - output cksum is in network order
3708 ipv4_hdr_cksum(uint8
*ip
, int ip_len
)
3714 ASSERT(ip_len
>= IPV4_MIN_HEADER_LEN
);
3716 /* partial cksum skipping the hdr_chksum field */
3717 sum
= ip_cksum_partial(sum
, ptr
, OFFSETOF(struct ipv4_hdr
, hdr_chksum
));
3718 ptr
+= OFFSETOF(struct ipv4_hdr
, hdr_chksum
) + 2;
3720 /* return calculated chksum */
3721 return ip_cksum(sum
, ptr
, ip_len
- OFFSETOF(struct ipv4_hdr
, src_ip
));
3724 /* calculate TCP header checksum using partial sum */
3726 tcp_hdr_chksum(uint32 sum
, uint8
*tcp_hdr
, uint16 tcp_len
)
3728 uint8
*ptr
= tcp_hdr
;
3730 ASSERT(tcp_hdr
!= NULL
);
3731 ASSERT(tcp_len
>= TCP_MIN_HEADER_LEN
);
3733 /* partial TCP cksum skipping the chksum field */
3734 sum
= ip_cksum_partial(sum
, ptr
, OFFSETOF(struct bcmtcp_hdr
, chksum
));
3735 ptr
+= OFFSETOF(struct bcmtcp_hdr
, chksum
) + 2;
3737 /* return calculated chksum */
3738 return ip_cksum(sum
, ptr
, tcp_len
- OFFSETOF(struct bcmtcp_hdr
, urg_ptr
));
3741 struct tcp_pseudo_hdr
{
3742 uint8 src_ip
[IPV4_ADDR_LEN
]; /* Source IP Address */
3743 uint8 dst_ip
[IPV4_ADDR_LEN
]; /* Destination IP Address */
3749 /* calculate IPv4 TCP header checksum
3750 * - input ip and tcp points to IP and TCP header in network order
3751 * - output cksum is in network order
3754 ipv4_tcp_hdr_cksum(uint8
*ip
, uint8
*tcp
, uint16 tcp_len
)
3756 struct ipv4_hdr
*ip_hdr
= (struct ipv4_hdr
*)ip
;
3757 struct tcp_pseudo_hdr tcp_ps
;
3761 ASSERT(tcp
!= NULL
);
3762 ASSERT(tcp_len
>= TCP_MIN_HEADER_LEN
);
3764 /* pseudo header cksum */
3765 memset(&tcp_ps
, 0, sizeof(tcp_ps
));
3766 memcpy(&tcp_ps
.dst_ip
, ip_hdr
->dst_ip
, IPV4_ADDR_LEN
);
3767 memcpy(&tcp_ps
.src_ip
, ip_hdr
->src_ip
, IPV4_ADDR_LEN
);
3769 tcp_ps
.prot
= ip_hdr
->prot
;
3770 tcp_ps
.tcp_size
= hton16(tcp_len
);
3771 sum
= ip_cksum_partial(sum
, (uint8
*)&tcp_ps
, sizeof(tcp_ps
));
3773 /* return calculated TCP header chksum */
3774 return tcp_hdr_chksum(sum
, tcp
, tcp_len
);
3777 struct ipv6_pseudo_hdr
{
3778 uint8 saddr
[IPV6_ADDR_LEN
];
3779 uint8 daddr
[IPV6_ADDR_LEN
];
3785 /* calculate IPv6 TCP header checksum
3786 * - input ipv6 and tcp points to IPv6 and TCP header in network order
3787 * - output cksum is in network order
3790 ipv6_tcp_hdr_cksum(uint8
*ipv6
, uint8
*tcp
, uint16 tcp_len
)
3792 struct ipv6_hdr
*ipv6_hdr
= (struct ipv6_hdr
*)ipv6
;
3793 struct ipv6_pseudo_hdr ipv6_pseudo
;
3796 ASSERT(ipv6
!= NULL
);
3797 ASSERT(tcp
!= NULL
);
3798 ASSERT(tcp_len
>= TCP_MIN_HEADER_LEN
);
3800 /* pseudo header cksum */
3801 memset((char *)&ipv6_pseudo
, 0, sizeof(ipv6_pseudo
));
3802 memcpy((char *)ipv6_pseudo
.saddr
, (char *)ipv6_hdr
->saddr
.addr
,
3803 sizeof(ipv6_pseudo
.saddr
));
3804 memcpy((char *)ipv6_pseudo
.daddr
, (char *)ipv6_hdr
->daddr
.addr
,
3805 sizeof(ipv6_pseudo
.daddr
));
3806 ipv6_pseudo
.payload_len
= ipv6_hdr
->payload_len
;
3807 ipv6_pseudo
.next_hdr
= ipv6_hdr
->nexthdr
;
3808 sum
= ip_cksum_partial(sum
, (uint8
*)&ipv6_pseudo
, sizeof(ipv6_pseudo
));
3810 /* return calculated TCP header chksum */
3811 return tcp_hdr_chksum(sum
, tcp
, tcp_len
);
3814 void *_bcmutils_dummy_fn
= NULL
;
3816 /* GROUP 1 --- start
3817 * These function under GROUP 1 are general purpose functions to do complex number
3818 * calculations and square root calculation.
3821 uint32
sqrt_int(uint32 value
)
3823 uint32 root
= 0, shift
= 0;
3825 /* Compute integer nearest to square root of input integer value */
3826 for (shift
= 0; shift
< 32; shift
+= 2) {
3827 if (((0x40000000 >> shift
) + root
) <= value
) {
3828 value
-= ((0x40000000 >> shift
) + root
);
3829 root
= (root
>> 1) | (0x40000000 >> shift
);
3836 /* round to the nearest integer */
3837 if (root
< value
) ++root
;
3841 /* GROUP 1 --- end */
3843 /* read/write field in a consecutive bits in an octet array.
3844 * 'addr' is the octet array's start byte address
3845 * 'size' is the octet array's byte size
3846 * 'stbit' is the value's start bit offset
3847 * 'nbits' is the value's bit size
3848 * This set of utilities are for convenience. Don't use them
3849 * in time critical/data path as there's a great overhead in them.
3852 setbits(uint8
*addr
, uint size
, uint stbit
, uint nbits
, uint32 val
)
3854 uint fbyte
= stbit
>> 3; /* first byte */
3855 uint lbyte
= (stbit
+ nbits
- 1) >> 3; /* last byte */
3856 uint fbit
= stbit
& 7; /* first bit in the first byte */
3857 uint rbits
= (nbits
> 8 - fbit
?
3858 nbits
- (8 - fbit
) :
3859 0) & 7; /* remaining bits of the last byte when not 0 */
3863 BCM_REFERENCE(size
);
3865 ASSERT(fbyte
< size
);
3866 ASSERT(lbyte
< size
);
3867 ASSERT(nbits
<= (sizeof(val
) << 3));
3869 /* all bits are in the same byte */
3870 if (fbyte
== lbyte
) {
3871 mask
= ((1 << nbits
) - 1) << fbit
;
3872 addr
[fbyte
] &= ~mask
;
3873 addr
[fbyte
] |= (uint8
)(val
<< fbit
);
3877 /* first partial byte */
3879 mask
= (0xff << fbit
);
3880 addr
[fbyte
] &= ~mask
;
3881 addr
[fbyte
] |= (uint8
)(val
<< fbit
);
3883 nbits
-= (8 - fbit
);
3884 fbyte
++; /* first full byte */
3887 /* last partial byte */
3889 mask
= (1 << rbits
) - 1;
3890 addr
[lbyte
] &= ~mask
;
3891 addr
[lbyte
] |= (uint8
)(val
>> (nbits
- rbits
));
3892 lbyte
--; /* last full byte */
3895 /* remaining full byte(s) */
3896 for (byte
= fbyte
; byte
<= lbyte
; byte
++) {
3897 addr
[byte
] = (uint8
)val
;
3903 getbits(const uint8
*addr
, uint size
, uint stbit
, uint nbits
)
3905 uint fbyte
= stbit
>> 3; /* first byte */
3906 uint lbyte
= (stbit
+ nbits
- 1) >> 3; /* last byte */
3907 uint fbit
= stbit
& 7; /* first bit in the first byte */
3908 uint rbits
= (nbits
> 8 - fbit
?
3909 nbits
- (8 - fbit
) :
3910 0) & 7; /* remaining bits of the last byte when not 0 */
3912 uint bits
= 0; /* bits in first partial byte */
3916 BCM_REFERENCE(size
);
3918 ASSERT(fbyte
< size
);
3919 ASSERT(lbyte
< size
);
3920 ASSERT(nbits
<= (sizeof(val
) << 3));
3922 /* all bits are in the same byte */
3923 if (fbyte
== lbyte
) {
3924 mask
= ((1 << nbits
) - 1) << fbit
;
3925 val
= (addr
[fbyte
] & mask
) >> fbit
;
3929 /* first partial byte */
3932 mask
= (0xff << fbit
);
3933 val
|= (addr
[fbyte
] & mask
) >> fbit
;
3934 fbyte
++; /* first full byte */
3937 /* last partial byte */
3939 mask
= (1 << rbits
) - 1;
3940 val
|= (addr
[lbyte
] & mask
) << (nbits
- rbits
);
3941 lbyte
--; /* last full byte */
3944 /* remaining full byte(s) */
3945 for (byte
= fbyte
; byte
<= lbyte
; byte
++) {
3946 val
|= (addr
[byte
] << (((byte
- fbyte
) << 3) + bits
));
3954 /** allocate variable sized data with 'size' bytes. note: vld should NOT be null.
3957 bcm_vdata_alloc(osl_t
*osh
, var_len_data_t
*vld
, uint32 size
)
3959 int ret
= BCME_ERROR
;
3967 /* trying to allocate twice? */
3968 if (vld
->vdata
!= NULL
) {
3973 /* trying to allocate 0 size? */
3980 dat
= MALLOCZ(osh
, size
);
3992 /** free memory associated with variable sized data. note: vld should NOT be null.
3995 bcm_vdata_free(osl_t
*osh
, var_len_data_t
*vld
)
3997 int ret
= BCME_ERROR
;
4005 MFREE(osh
, vld
->vdata
, vld
->vlen
);
4014 #endif /* BCMDRIVER */
4016 /* Count the number of elements not matching a given value in a null terminated array */
4018 array_value_mismatch_count(uint8 value
, uint8
*array
, int array_size
)
4023 for (i
= 0; i
< array_size
; i
++) {
4024 /* exit if a null terminator is found */
4025 if (array
[i
] == 0) {
4028 if (array
[i
] != value
) {
4035 /* Count the number of non-zero elements in an uint8 array */
4037 array_nonzero_count(uint8
*array
, int array_size
)
4039 return array_value_mismatch_count(0, array
, array_size
);
4042 /* Count the number of non-zero elements in an int16 array */
4044 array_nonzero_count_int16(int16
*array
, int array_size
)
4049 for (i
= 0; i
< array_size
; i
++) {
4050 if (array
[i
] != 0) {
4057 /* Count the number of zero elements in an uint8 array */
4059 array_zero_count(uint8
*array
, int array_size
)
4064 for (i
= 0; i
< array_size
; i
++) {
4065 if (array
[i
] == 0) {
4072 /* Validate an array that can be 1 of 2 data types.
4073 * One of array1 or array2 should be non-NULL. The other should be NULL.
4076 verify_ordered_array(uint8
*array1
, int16
*array2
, int array_size
,
4077 int range_lo
, int range_hi
, bool err_if_no_zero_term
, bool is_ordered
)
4084 ret
= err_if_no_zero_term
? BCME_NOTFOUND
: BCME_OK
;
4087 * - values are in strict descending order.
4088 * - values are within the valid range.
4090 for (i
= 0; i
< array_size
; i
++) {
4092 val
= (int)array1
[i
];
4093 } else if (array2
) {
4094 val
= (int)array2
[i
];
4096 /* both array parameters are NULL */
4097 return BCME_NOTFOUND
;
4100 /* array is zero-terminated */
4105 if (is_ordered
&& i
> 0 && val
>= prev_val
) {
4106 /* array is not in descending order */
4107 ret
= BCME_BADOPTION
;
4112 if (val
< range_lo
|| val
> range_hi
) {
4113 /* array value out of range */
4122 /* Validate an ordered uint8 configuration array */
4124 verify_ordered_array_uint8(uint8
*array
, int array_size
,
4125 uint8 range_lo
, uint8 range_hi
)
4127 return verify_ordered_array(array
, NULL
, array_size
, (int)range_lo
, (int)range_hi
,
4131 /* Validate an ordered int16 non-zero-terminated configuration array */
4133 verify_ordered_array_int16(int16
*array
, int array_size
,
4134 int16 range_lo
, int16 range_hi
)
4136 return verify_ordered_array(NULL
, array
, array_size
, (int)range_lo
, (int)range_hi
,
4140 /* Validate all values in an array are in range */
4142 verify_array_values(uint8
*array
, int array_size
,
4143 int range_lo
, int range_hi
, bool zero_terminated
)
4150 * - values are in strict descending order.
4151 * - values are within the valid range.
4153 for (i
= 0; i
< array_size
; i
++) {
4154 val
= (int)array
[i
];
4155 if (val
== 0 && zero_terminated
) {
4159 if (val
< range_lo
|| val
> range_hi
) {
4160 /* array value out of range */