From 297b60346df8beafee954a0fd7c2d64f33f3b9bc Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 11 May 2024 01:44:05 +0000
Subject: [PATCH] rtl8211F_led_control
---
kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c | 4133 ++++++++++++++++++++++++++++++++++-------------------------
1 files changed, 2,403 insertions(+), 1,730 deletions(-)
diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c
index 2a8aa0a..906b92a 100644
--- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c
+++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmutils.c
@@ -1,15 +1,16 @@
-/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver O/S-independent utility routines
*
- * Copyright (C) 1999-2019, Broadcom Corporation
- *
+ * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation
+ *
+ * Copyright (C) 1999-2017, Broadcom Corporation
+ *
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
- *
+ *
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -17,7 +18,7 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
- *
+ *
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
@@ -25,7 +26,7 @@
*
* <<Broadcom-WL-IPTag/Open:>>
*
- * $Id: bcmutils.c 692666 2018-07-30 08:58:07Z $
+ * $Id: bcmutils.c 702105 2017-05-30 19:10:39Z $
*/
#include <bcm_cfg.h>
@@ -33,7 +34,6 @@
#include <bcmdefs.h>
#include <stdarg.h>
#ifdef BCMDRIVER
-
#include <osl.h>
#include <bcmutils.h>
@@ -41,99 +41,39 @@
#include <stdio.h>
#include <string.h>
+#include <bcm_math.h>
#include <bcmutils.h>
#if defined(BCMEXTSUP)
#include <bcm_osl.h>
-#endif
+#endif // endif
#ifndef ASSERT
#define ASSERT(exp)
-#endif
+#endif // endif
#endif /* !BCMDRIVER */
+#ifdef WL_UNITTEST
+#ifdef ASSERT
+#undef ASSERT
+#endif /* ASSERT */
+#define ASSERT(exp)
+#endif /* WL_UNITTEST */
+
+#include <bcmstdlib_s.h>
#include <bcmendian.h>
#include <bcmdevs.h>
-#include <proto/ethernet.h>
-#include <proto/vlan.h>
-#include <proto/bcmip.h>
-#include <proto/802.1d.h>
-#include <proto/802.11.h>
-
-
-void *_bcmutils_dummy_fn = NULL;
-
-
-
+#include <ethernet.h>
+#include <vlan.h>
+#include <bcmip.h>
+#include <802.1d.h>
+#include <802.11.h>
+#include <bcmip.h>
+#include <bcmipv6.h>
+#include <bcmtcp.h>
#ifdef BCMDRIVER
-
-
-
-/* copy a pkt buffer chain into a buffer */
-uint
-pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
-{
- uint n, ret = 0;
-
- if (len < 0)
- len = 4096; /* "infinite" */
-
- /* skip 'offset' bytes */
- for (; p && offset; p = PKTNEXT(osh, p)) {
- if (offset < (uint)PKTLEN(osh, p))
- break;
- offset -= PKTLEN(osh, p);
- }
-
- if (!p)
- return 0;
-
- /* copy the data */
- for (; p && len; p = PKTNEXT(osh, p)) {
- n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
- bcopy(PKTDATA(osh, p) + offset, buf, n);
- buf += n;
- len -= n;
- ret += n;
- offset = 0;
- }
-
- return ret;
-}
-
-/* copy a buffer into a pkt buffer chain */
-uint
-pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
-{
- uint n, ret = 0;
-
-
- /* skip 'offset' bytes */
- for (; p && offset; p = PKTNEXT(osh, p)) {
- if (offset < (uint)PKTLEN(osh, p))
- break;
- offset -= PKTLEN(osh, p);
- }
-
- if (!p)
- return 0;
-
- /* copy the data */
- for (; p && len; p = PKTNEXT(osh, p)) {
- n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
- bcopy(buf, PKTDATA(osh, p) + offset, n);
- buf += n;
- len -= n;
- ret += n;
- offset = 0;
- }
-
- return ret;
-}
-
-
/* return total length of buffer chain */
uint BCMFASTPATH
@@ -145,14 +85,14 @@
total = 0;
for (; p; p = PKTNEXT(osh, p)) {
len = PKTLEN(osh, p);
- total += len;
+ total += (uint)len;
#ifdef BCMLFRAG
if (BCMLFRAG_ENAB()) {
if (PKTISFRAG(osh, p)) {
total += PKTFRAGTOTLEN(osh, p);
}
}
-#endif
+#endif // endif
}
return (total);
@@ -182,41 +122,71 @@
cnt += PKTFRAGTOTNUM(osh, p);
}
}
-#endif
+#endif // endif
}
return cnt;
}
-
-/* count segments of a chained packet */
-uint BCMFASTPATH
-pktsegcnt_war(osl_t *osh, void *p)
+/* copy a pkt buffer chain into a buffer */
+uint
+pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
{
- uint cnt;
- uint8 *pktdata;
- uint len, remain, align64;
+ uint n, ret = 0;
- for (cnt = 0; p; p = PKTNEXT(osh, p)) {
- cnt++;
- len = PKTLEN(osh, p);
- if (len > 128) {
- pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */
- /* Check for page boundary straddle (2048B) */
- if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
- cnt++;
+ if (len < 0)
+ len = 4096; /* "infinite" */
- align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */
- align64 = (64 - align64) & 0x3f;
- len -= align64; /* bytes from aligned 64B to end */
- /* if aligned to 128B, check for MOD 128 between 1 to 4B */
- remain = len % 128;
- if (remain > 0 && remain <= 4)
- cnt++; /* add extra seg */
- }
+ /* skip 'offset' bytes */
+ for (; p && offset; p = PKTNEXT(osh, p)) {
+ if (offset < (uint)PKTLEN(osh, p))
+ break;
+ offset -= (uint)PKTLEN(osh, p);
}
- return cnt;
+ if (!p)
+ return 0;
+
+ /* copy the data */
+ for (; p && len; p = PKTNEXT(osh, p)) {
+ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
+ bcopy(PKTDATA(osh, p) + offset, buf, n);
+ buf += n;
+ len -= n;
+ ret += n;
+ offset = 0;
+ }
+
+ return ret;
+}
+
+/* copy a buffer into a pkt buffer chain */
+uint
+pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
+{
+ uint n, ret = 0;
+
+ /* skip 'offset' bytes */
+ for (; p && offset; p = PKTNEXT(osh, p)) {
+ if (offset < (uint)PKTLEN(osh, p))
+ break;
+ offset -= (uint)PKTLEN(osh, p);
+ }
+
+ if (!p)
+ return 0;
+
+ /* copy the data */
+ for (; p && len; p = PKTNEXT(osh, p)) {
+ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
+ bcopy(buf, PKTDATA(osh, p) + offset, n);
+ buf += n;
+ len -= n;
+ ret += n;
+ offset = 0;
+ }
+
+ return ret;
}
uint8 * BCMFASTPATH
@@ -232,13 +202,12 @@
for (; p; p = PKTNEXT(osh, p)) {
pdata = (uint8 *) PKTDATA(osh, p);
pkt_off = offset - len;
- len += PKTLEN(osh, p);
+ len += (uint)PKTLEN(osh, p);
if (len > offset)
break;
}
return (uint8*) (pdata+pkt_off);
}
-
/* given a offset in pdata, find the pkt seg hdr */
void *
@@ -251,14 +220,1479 @@
return NULL;
for (; p; p = PKTNEXT(osh, p)) {
- len += PKTLEN(osh, p);
+ len += (uint)PKTLEN(osh, p);
if (len > offset)
break;
}
return p;
}
+void
+bcm_mdelay(uint ms)
+{
+ uint i;
+
+ for (i = 0; i < ms; i++) {
+ OSL_DELAY(1000);
+ }
+}
+
+#if defined(DHD_DEBUG)
+/* pretty hex print a pkt buffer chain */
+void
+prpkt(const char *msg, osl_t *osh, void *p0)
+{
+ void *p;
+
+ if (msg && (msg[0] != '\0'))
+ printf("%s:\n", msg);
+
+ for (p = p0; p; p = PKTNEXT(osh, p))
+ prhex(NULL, PKTDATA(osh, p), (uint)PKTLEN(osh, p));
+}
+#endif // endif
+
+/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
+ * Also updates the inplace vlan tag if requested.
+ * For debugging, it returns an indication of what it did.
+ */
+uint BCMFASTPATH
+pktsetprio(void *pkt, bool update_vtag)
+{
+ struct ether_header *eh;
+ struct ethervlan_header *evh;
+ uint8 *pktdata;
+ uint priority = 0;
+ uint rc = 0;
+
+ pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
+ ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
+
+ eh = (struct ether_header *) pktdata;
+
+ if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
+ uint16 vlan_tag;
+ uint vlan_prio, dscp_prio = 0;
+
+ evh = (struct ethervlan_header *)eh;
+
+ vlan_tag = ntoh16(evh->vlan_tag);
+ vlan_prio = (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
+
+ if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
+ (evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
+ uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
+ uint8 tos_tc = (uint8)IP_TOS46(ip_body);
+ dscp_prio = tos_tc >> IPV4_TOS_PREC_SHIFT;
+ }
+
+ /* DSCP priority gets precedence over 802.1P (vlan tag) */
+ if (dscp_prio != 0) {
+ priority = dscp_prio;
+ rc |= PKTPRIO_VDSCP;
+ } else {
+ priority = vlan_prio;
+ rc |= PKTPRIO_VLAN;
+ }
+ /*
+ * If the DSCP priority is not the same as the VLAN priority,
+ * then overwrite the priority field in the vlan tag, with the
+ * DSCP priority value. This is required for Linux APs because
+ * the VLAN driver on Linux, overwrites the skb->priority field
+ * with the priority value in the vlan tag
+ */
+ if (update_vtag && (priority != vlan_prio)) {
+ vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
+ vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
+ evh->vlan_tag = hton16(vlan_tag);
+ rc |= PKTPRIO_UPD;
+ }
+#if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING)
+ } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
+ priority = PRIO_8021D_NC;
+ rc = PKTPRIO_DSCP;
+#endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */
+ } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
+ (eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
+ uint8 *ip_body = pktdata + sizeof(struct ether_header);
+ uint8 tos_tc = (uint8)IP_TOS46(ip_body);
+ uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
+ switch (dscp) {
+ case DSCP_EF:
+ case DSCP_VA:
+ priority = PRIO_8021D_VO;
+ break;
+ case DSCP_AF31:
+ case DSCP_AF32:
+ case DSCP_AF33:
+ case DSCP_CS3:
+ priority = PRIO_8021D_CL;
+ break;
+ case DSCP_AF21:
+ case DSCP_AF22:
+ case DSCP_AF23:
+ priority = PRIO_8021D_EE;
+ break;
+ case DSCP_AF11:
+ case DSCP_AF12:
+ case DSCP_AF13:
+ case DSCP_CS2:
+ priority = PRIO_8021D_BE;
+ break;
+ case DSCP_CS6:
+ case DSCP_CS7:
+ priority = PRIO_8021D_NC;
+ break;
+ default:
+ priority = tos_tc >> IPV4_TOS_PREC_SHIFT;
+ break;
+ }
+
+ rc |= PKTPRIO_DSCP;
+ }
+
+ ASSERT(priority <= MAXPRIO);
+ PKTSETPRIO(pkt, (int)priority);
+ return (rc | priority);
+}
+
+/* lookup user priority for specified DSCP */
+static uint8
+dscp2up(uint8 *up_table, uint8 dscp)
+{
+ uint8 user_priority = 255;
+
+ /* lookup up from table if parameters valid */
+ if (up_table != NULL && dscp < UP_TABLE_MAX) {
+ user_priority = up_table[dscp];
+ }
+
+ /* 255 is unused value so return up from dscp */
+ if (user_priority == 255) {
+ user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
+ }
+
+ return user_priority;
+}
+
+/* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
+uint BCMFASTPATH
+pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag)
+{
+ if (up_table) {
+ uint8 *pktdata;
+ uint pktlen;
+ uint8 dscp;
+ uint user_priority = 0;
+ uint rc = 0;
+
+ pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
+ pktlen = (uint)PKTLEN(OSH_NULL, pkt);
+
+ if (pktgetdscp(pktdata, pktlen, &dscp)) {
+ rc = PKTPRIO_DSCP;
+ user_priority = dscp2up(up_table, dscp);
+ PKTSETPRIO(pkt, (int)user_priority);
+ }
+
+ return (rc | user_priority);
+ } else {
+ return pktsetprio(pkt, update_vtag);
+ }
+}
+
+/* Returns TRUE and DSCP if IP header found, FALSE otherwise.
+ */
+bool BCMFASTPATH
+pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
+{
+ struct ether_header *eh;
+ struct ethervlan_header *evh;
+ uint8 *ip_body;
+ bool rc = FALSE;
+
+ /* minimum length is ether header and IP header */
+ if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
+ return FALSE;
+
+ eh = (struct ether_header *) pktdata;
+
+ if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
+ ip_body = pktdata + sizeof(struct ether_header);
+ *dscp = (uint8)IP_DSCP46(ip_body);
+ rc = TRUE;
+ }
+ else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
+ evh = (struct ethervlan_header *)eh;
+
+ /* minimum length is ethervlan header and IP header */
+ if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
+ evh->ether_type == HTON16(ETHER_TYPE_IP)) {
+ ip_body = pktdata + sizeof(struct ethervlan_header);
+ *dscp = (uint8)IP_DSCP46(ip_body);
+ rc = TRUE;
+ }
+ }
+
+ return rc;
+}
+
+/* usr_prio range from low to high with usr_prio value */
+static bool
+up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high)
+{
+ int i;
+
+ if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) {
+ return FALSE;
+ }
+
+ for (i = low; i <= high; i++) {
+ up_table[i] = usr_prio;
+ }
+
+ return TRUE;
+}
+
+/* set user priority table */
+int BCMFASTPATH
+wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie)
+{
+ uint8 len;
+
+ if (up_table == NULL || qos_map_ie == NULL) {
+ return BCME_ERROR;
+ }
+
+ /* clear table to check table was set or not */
+ memset(up_table, 0xff, UP_TABLE_MAX);
+
+ /* length of QoS Map IE must be 16+n*2, n is number of exceptions */
+ if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID &&
+ (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH &&
+ (len % 2) == 0) {
+ uint8 *except_ptr = (uint8 *)qos_map_ie->data;
+ uint8 except_len = len - QOS_MAP_FIXED_LENGTH;
+ uint8 *range_ptr = except_ptr + except_len;
+ uint8 i;
+
+ /* fill in ranges */
+ for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) {
+ uint8 low = range_ptr[i];
+ uint8 high = range_ptr[i + 1];
+ if (low == 255 && high == 255) {
+ continue;
+ }
+
+ if (!up_table_set(up_table, i / 2, low, high)) {
+ /* clear the table on failure */
+ memset(up_table, 0xff, UP_TABLE_MAX);
+ return BCME_ERROR;
+ }
+ }
+
+ /* update exceptions */
+ for (i = 0; i < except_len; i += 2) {
+ uint8 dscp = except_ptr[i];
+ uint8 usr_prio = except_ptr[i+1];
+
+ /* exceptions with invalid dscp/usr_prio are ignored */
+ up_table_set(up_table, usr_prio, dscp, dscp);
+ }
+ }
+
+ return BCME_OK;
+}
+
+/* The 0.5KB string table is not removed by compiler even though it's unused */
+
+static char bcm_undeferrstr[32];
+static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
+
+/* Convert the error codes into related error strings */
+const char *
+BCMRAMFN(bcmerrorstr)(int bcmerror)
+{
+ /* check if someone added a bcmerror code but forgot to add errorstring */
+ ASSERT((uint)ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
+
+ if (bcmerror > 0 || bcmerror < BCME_LAST) {
+ snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
+ return bcm_undeferrstr;
+ }
+
+ ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
+
+ return bcmerrorstrtable[-bcmerror];
+}
+
+/* iovar table lookup */
+/* could mandate sorted tables and do a binary search */
+const bcm_iovar_t*
+bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
+{
+ const bcm_iovar_t *vi;
+ const char *lookup_name;
+
+ /* skip any ':' delimited option prefixes */
+ lookup_name = strrchr(name, ':');
+ if (lookup_name != NULL)
+ lookup_name++;
+ else
+ lookup_name = name;
+
+ ASSERT(table != NULL);
+
+ for (vi = table; vi->name; vi++) {
+ if (!strcmp(vi->name, lookup_name))
+ return vi;
+ }
+ /* ran to end of table */
+
+ return NULL; /* var name not found */
+}
+
+int
+bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
+{
+ int bcmerror = 0;
+ BCM_REFERENCE(arg);
+
+ /* length check on io buf */
+ switch (vi->type) {
+ case IOVT_BOOL:
+ case IOVT_INT8:
+ case IOVT_INT16:
+ case IOVT_INT32:
+ case IOVT_UINT8:
+ case IOVT_UINT16:
+ case IOVT_UINT32:
+ /* all integers are int32 sized args at the ioctl interface */
+ if (len < (int)sizeof(int)) {
+ bcmerror = BCME_BUFTOOSHORT;
+ }
+ break;
+
+ case IOVT_BUFFER:
+ /* buffer must meet minimum length requirement */
+ if (len < vi->minlen) {
+ bcmerror = BCME_BUFTOOSHORT;
+ }
+ break;
+
+ case IOVT_VOID:
+ if (!set) {
+ /* Cannot return nil... */
+ bcmerror = BCME_UNSUPPORTED;
+ }
+ break;
+
+ default:
+ /* unknown type for length check in iovar info */
+ ASSERT(0);
+ bcmerror = BCME_UNSUPPORTED;
+ }
+
+ return bcmerror;
+}
+
+#if !defined(_CFEZ_)
+/*
+ * Hierarchical Multiword bitmap based small id allocator.
+ *
+ * Multilevel hierarchy bitmap. (maximum 2 levels)
+ * First hierarchy uses a multiword bitmap to identify 32bit words in the
+ * second hierarchy that have at least a single bit set. Each bit in a word of
+ * the second hierarchy represents a unique ID that may be allocated.
+ *
+ * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
+ * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
+ * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
+ * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
+ * non-zero bitmap word carrying at least one free ID.
+ * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
+ * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
+ *
+ * Design Notes:
+ * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
+ * bits are computed each time on allocation and deallocation, requiring 4
+ * array indexed access and 3 arithmetic operations. When not defined, a runtime
+ * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
+ * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
+ * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
+ * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
+ *
+ * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
+ * size is fixed. No intention to support larger than 4K indice allocation. ID
+ * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
+ * with savings in not having to use an indirect access, had it been dynamically
+ * allocated.
+ */
+#define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */
+
+#define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
+#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
+#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
+#define BCM_MWBMAP_SHIFT_OP (5)
+#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
+#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
+#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
+
+/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
+#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
+#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
+
+#if defined(BCM_MWBMAP_DEBUG)
+#define BCM_MWBMAP_AUDIT(mwb) \
+ do { \
+ ASSERT((mwb != NULL) && \
+ (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
+ bcm_mwbmap_audit(mwb); \
+ } while (0)
+#define MWBMAP_ASSERT(exp) ASSERT(exp)
+#define MWBMAP_DBG(x) printf x
+#else /* !BCM_MWBMAP_DEBUG */
+#define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
+#define MWBMAP_ASSERT(exp) do {} while (0)
+#define MWBMAP_DBG(x)
+#endif /* !BCM_MWBMAP_DEBUG */
+
+typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
+ uint16 wmaps; /* Total number of words in free wd bitmap */
+ uint16 imaps; /* Total number of words in free id bitmap */
+ int32 ifree; /* Count of free indices. Used only in audits */
+ uint16 total; /* Total indices managed by multiword bitmap */
+
+ void * magic; /* Audit handle parameter from user */
+
+ uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */
+#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
+ int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+
+ uint32 id_bitmap[0]; /* Second level bitmap */
+} bcm_mwbmap_t;
+
+/* Incarnate a hierarchical multiword bitmap based small index allocator. */
+struct bcm_mwbmap *
+bcm_mwbmap_init(osl_t *osh, uint32 items_max)
+{
+ struct bcm_mwbmap * mwbmap_p;
+ uint32 wordix, size, words, extra;
+
+ /* Implementation Constraint: Uses 32bit word bitmap */
+ MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
+ MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
+ MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
+ MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
+
+ ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
+
+ /* Determine the number of words needed in the multiword bitmap */
+ extra = BCM_MWBMAP_MODOP(items_max);
+ words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
+
+ /* Allocate runtime state of multiword bitmap */
+ /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
+ size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
+ mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
+ if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
+ ASSERT(0);
+ goto error1;
+ }
+ memset(mwbmap_p, 0, size);
+
+ /* Initialize runtime multiword bitmap state */
+ mwbmap_p->imaps = (uint16)words;
+ mwbmap_p->ifree = (int32)items_max;
+ mwbmap_p->total = (uint16)items_max;
+
+ /* Setup magic, for use in audit of handle */
+ mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
+
+ /* Setup the second level bitmap of free indices */
+ /* Mark all indices as available */
+ for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
+ mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
+#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
+ mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ }
+
+ /* Ensure that extra indices are tagged as un-available */
+ if (extra) { /* fixup the free ids in last bitmap and wd_count */
+ uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
+ *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
+#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
+ mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ }
+
+ /* Setup the first level bitmap hierarchy */
+ extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
+ words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
+
+ mwbmap_p->wmaps = (uint16)words;
+
+ for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
+ mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
+ if (extra) {
+ uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
+ *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
+ }
+
+ return mwbmap_p;
+
+error1:
+ return BCM_MWBMAP_INVALID_HDL;
+}
+
+/* Release resources used by multiword bitmap based small index allocator. */
+void
+bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
+{
+ bcm_mwbmap_t * mwbmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
+ + (sizeof(uint32) * mwbmap_p->imaps));
+ return;
+}
+
+/* Allocate a unique small index using a multiword bitmap index allocator. */
+uint32 BCMFASTPATH
+bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 wordix, bitmap;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ /* Start with the first hierarchy */
+ for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
+
+ bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
+
+ if (bitmap != 0U) {
+
+ uint32 count, bitix, *bitmap_p;
+
+ bitmap_p = &mwbmap_p->wd_bitmap[wordix];
+
+ /* clear all except trailing 1 */
+ bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
+ MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
+ bcm_count_leading_zeros(bitmap));
+ bitix = (BCM_MWBMAP_BITS_WORD - 1)
+ - (uint32)bcm_count_leading_zeros(bitmap); /* use asm clz */
+ wordix = BCM_MWBMAP_MULOP(wordix) + bitix;
+
+ /* Clear bit if wd count is 0, without conditional branch */
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ mwbmap_p->wd_count[wordix]--;
+ count = (uint32)mwbmap_p->wd_count[wordix];
+ MWBMAP_ASSERT(count ==
+ (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ MWBMAP_ASSERT(count >= 0);
+
+ /* clear wd_bitmap bit if id_map count is 0 */
+ bitmap = ((uint32)(count == 0)) << BCM_MWBMAP_MODOP(bitix);
+
+ MWBMAP_DBG((
+ "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
+
+ *bitmap_p ^= bitmap;
+
+ /* Use bitix in the second hierarchy */
+ bitmap_p = &mwbmap_p->id_bitmap[wordix];
+
+ bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
+ MWBMAP_ASSERT(bitmap != 0U);
+
+ /* clear all except trailing 1 */
+ bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
+ MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
+ bcm_count_leading_zeros(bitmap));
+ bitix = BCM_MWBMAP_MULOP(wordix)
+ + (BCM_MWBMAP_BITS_WORD - 1)
+ - (uint32)bcm_count_leading_zeros(bitmap); /* use asm clz */
+
+ mwbmap_p->ifree--; /* decrement system wide free count */
+ MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
+
+ MWBMAP_DBG((
+ "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
+ mwbmap_p->ifree));
+
+ *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
+
+ return bitix;
+ }
+ }
+
+ ASSERT(mwbmap_p->ifree == 0);
+
+ return BCM_MWBMAP_INVALID_IDX;
+}
+
+/* Force an index at a specified position to be in use */
+void
+bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 count, wordix, bitmap, *bitmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ ASSERT(bitix < mwbmap_p->total);
+
+ /* Start with second hierarchy */
+ wordix = BCM_MWBMAP_DIVOP(bitix);
+ bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
+ bitmap_p = &mwbmap_p->id_bitmap[wordix];
+
+ ASSERT((*bitmap_p & bitmap) == bitmap);
+
+ mwbmap_p->ifree--; /* update free count */
+ ASSERT(mwbmap_p->ifree >= 0);
+
+ MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
+ mwbmap_p->ifree));
+
+ *bitmap_p ^= bitmap; /* mark as in use */
+
+ /* Update first hierarchy */
+ bitix = wordix;
+
+ wordix = BCM_MWBMAP_DIVOP(bitix);
+ bitmap_p = &mwbmap_p->wd_bitmap[wordix];
+
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ mwbmap_p->wd_count[bitix]--;
+ count = (uint32)mwbmap_p->wd_count[bitix];
+ MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ MWBMAP_ASSERT(count >= 0);
+
+ bitmap = (uint32)(count == 0) << BCM_MWBMAP_MODOP(bitix);
+
+ MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
+ BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
+ (*bitmap_p) ^ bitmap, count));
+
+ *bitmap_p ^= bitmap; /* mark as in use */
+
+ return;
+}
+
+/* Free a previously allocated index back into the multiword bitmap allocator */
+void BCMFASTPATH
+bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 wordix, bitmap, *bitmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ ASSERT(bitix < mwbmap_p->total);
+
+ /* Start with second level hierarchy */
+ wordix = BCM_MWBMAP_DIVOP(bitix);
+ bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
+ bitmap_p = &mwbmap_p->id_bitmap[wordix];
+
+ ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */
+
+ mwbmap_p->ifree++; /* update free count */
+ ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
+
+ MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
+ mwbmap_p->ifree));
+
+ *bitmap_p |= bitmap; /* mark as available */
+
+ /* Now update first level hierarchy */
+
+ bitix = wordix;
+
+ wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
+ bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
+ bitmap_p = &mwbmap_p->wd_bitmap[wordix];
+
+#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
+ mwbmap_p->wd_count[bitix]++;
+#endif // endif
+
+#if defined(BCM_MWBMAP_DEBUG)
+ {
+ uint32 count;
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ count = mwbmap_p->wd_count[bitix];
+ MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+
+ MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
+
+ MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
+ }
+#endif /* BCM_MWBMAP_DEBUG */
+
+ *bitmap_p |= bitmap;
+
+ return;
+}
+
+/* Fetch the toal number of free indices in the multiword bitmap allocator */
+uint32
+bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
+{
+ bcm_mwbmap_t * mwbmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ ASSERT(mwbmap_p->ifree >= 0);
+
+ return (uint32)mwbmap_p->ifree;
+}
+
+/* Determine whether an index is inuse or free */
+bool
+bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 wordix, bitmap;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ ASSERT(bitix < mwbmap_p->total);
+
+ wordix = BCM_MWBMAP_DIVOP(bitix);
+ bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
+
+ return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
+}
+
+/* Debug dump a multiword bitmap allocator */
+void
+bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
+{
+ uint32 ix, count;
+ bcm_mwbmap_t * mwbmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n",
+ OSL_OBFUSCATE_BUF((void *)mwbmap_p),
+ mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
+ for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
+ printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
+ bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
+ printf("\n");
+ }
+ for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ count = (uint32)mwbmap_p->wd_count[ix];
+ MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
+ bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
+ printf("\n");
+ }
+
+ return;
+}
+
+/* Audit a hierarchical multiword bitmap */
+void
+bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
+
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
+
+ bitmap_p = &mwbmap_p->wd_bitmap[wordix];
+
+ for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
+ if ((*bitmap_p) & (1 << bitix)) {
+ idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ count = (uint32)mwbmap_p->wd_count[idmap_ix];
+ ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ ASSERT(count != 0U);
+ free_cnt += count;
+ }
+ }
+ }
+
+ ASSERT((int)free_cnt == mwbmap_p->ifree);
+}
+/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
+
+/* Simple 16bit Id allocator using a stack implementation. */
+typedef struct id16_map {
+ uint32 failures; /* count of failures */
+ void *dbg; /* debug placeholder */
+ uint16 total; /* total number of ids managed by allocator */
+ uint16 start; /* start value of 16bit ids to be managed */
+ int stack_idx; /* index into stack of available ids */
+ uint16 stack[0]; /* stack of 16 bit ids */
+} id16_map_t;
+
+#define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \
+ (sizeof(uint16) * (items)))
+
+#if defined(BCM_DBG)
+
+/* Uncomment BCM_DBG_ID16 to debug double free */
+/* #define BCM_DBG_ID16 */
+
+typedef struct id16_map_dbg {
+ uint16 total;
+ bool avail[0];
+} id16_map_dbg_t;
+#define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \
+ (sizeof(bool) * (items)))
+#define ID16_MAP_MSG(x) print x
+#else
+#define ID16_MAP_MSG(x)
+#endif /* BCM_DBG */
+
+void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
+id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
+{
+ uint16 idx, val16;
+ id16_map_t * id16_map;
+
+ ASSERT(total_ids > 0);
+
+ /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
+ * with random values.
+ */
+ ASSERT((start_val16 == ID16_UNDEFINED) ||
+ (start_val16 + total_ids) < ID16_INVALID);
+
+ id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
+ if (id16_map == NULL) {
+ return NULL;
+ }
+
+ id16_map->total = total_ids;
+ id16_map->start = start_val16;
+ id16_map->failures = 0;
+ id16_map->dbg = NULL;
+
+ /*
+ * Populate stack with 16bit id values, commencing with start_val16.
+ * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
+ */
+ id16_map->stack_idx = -1;
+
+ if (id16_map->start != ID16_UNDEFINED) {
+ val16 = start_val16;
+
+ for (idx = 0; idx < total_ids; idx++, val16++) {
+ id16_map->stack_idx = idx;
+ id16_map->stack[id16_map->stack_idx] = val16;
+ }
+ }
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->start != ID16_UNDEFINED) {
+ id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
+
+ if (id16_map->dbg) {
+ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+ id16_map_dbg->total = total_ids;
+ for (idx = 0; idx < total_ids; idx++) {
+ id16_map_dbg->avail[idx] = TRUE;
+ }
+ }
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+ return (void *)id16_map;
+}
+
+void * /* Destruct an id16 allocator instance */
+id16_map_fini(osl_t *osh, void * id16_map_hndl)
+{
+ uint16 total_ids;
+ id16_map_t * id16_map;
+
+ if (id16_map_hndl == NULL)
+ return NULL;
+
+ id16_map = (id16_map_t *)id16_map_hndl;
+
+ total_ids = id16_map->total;
+ ASSERT(total_ids > 0);
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->dbg) {
+ MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
+ id16_map->dbg = NULL;
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+ id16_map->total = 0;
+ MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
+
+ return NULL;
+}
+
+void
+id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
+{
+ uint16 idx, val16;
+ id16_map_t * id16_map;
+
+ ASSERT(total_ids > 0);
+ /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
+ * with random values.
+ */
+ ASSERT((start_val16 == ID16_UNDEFINED) ||
+ (start_val16 + total_ids) < ID16_INVALID);
+
+ id16_map = (id16_map_t *)id16_map_hndl;
+ if (id16_map == NULL) {
+ return;
+ }
+
+ id16_map->total = total_ids;
+ id16_map->start = start_val16;
+ id16_map->failures = 0;
+
+ /* Populate stack with 16bit id values, commencing with start_val16 */
+ id16_map->stack_idx = -1;
+
+ if (id16_map->start != ID16_UNDEFINED) {
+ val16 = start_val16;
+
+ for (idx = 0; idx < total_ids; idx++, val16++) {
+ id16_map->stack_idx = idx;
+ id16_map->stack[id16_map->stack_idx] = val16;
+ }
+ }
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->start != ID16_UNDEFINED) {
+ if (id16_map->dbg) {
+ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+ id16_map_dbg->total = total_ids;
+ for (idx = 0; idx < total_ids; idx++) {
+ id16_map_dbg->avail[idx] = TRUE;
+ }
+ }
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+}
+
+uint16 BCMFASTPATH /* Allocate a unique 16bit id */
+id16_map_alloc(void * id16_map_hndl)
+{
+ uint16 val16;
+ id16_map_t * id16_map;
+
+ ASSERT(id16_map_hndl != NULL);
+ if (!id16_map_hndl) {
+ return ID16_INVALID;
+ }
+ id16_map = (id16_map_t *)id16_map_hndl;
+
+ ASSERT(id16_map->total > 0);
+
+ if (id16_map->stack_idx < 0) {
+ id16_map->failures++;
+ return ID16_INVALID;
+ }
+
+ val16 = id16_map->stack[id16_map->stack_idx];
+ id16_map->stack_idx--;
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ ASSERT((id16_map->start == ID16_UNDEFINED) ||
+ (val16 < (id16_map->start + id16_map->total)));
+
+ if (id16_map->dbg) { /* Validate val16 */
+ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+ ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
+ id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+ return val16;
+}
+
+void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
+id16_map_free(void * id16_map_hndl, uint16 val16)
+{
+ id16_map_t * id16_map;
+
+ ASSERT(id16_map_hndl != NULL);
+
+ id16_map = (id16_map_t *)id16_map_hndl;
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ ASSERT((id16_map->start == ID16_UNDEFINED) ||
+ (val16 < (id16_map->start + id16_map->total)));
+
+ if (id16_map->dbg) { /* Validate val16 */
+ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+ ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
+ id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+ id16_map->stack_idx++;
+ id16_map->stack[id16_map->stack_idx] = val16;
+}
+
+uint32 /* Returns number of failures to allocate an unique id16 */
+id16_map_failures(void * id16_map_hndl)
+{
+ ASSERT(id16_map_hndl != NULL);
+ return ((id16_map_t *)id16_map_hndl)->failures;
+}
+
+bool
+id16_map_audit(void * id16_map_hndl)
+{
+ int idx;
+ int insane = 0;
+ id16_map_t * id16_map;
+
+ ASSERT(id16_map_hndl != NULL);
+ if (!id16_map_hndl) {
+ goto done;
+ }
+ id16_map = (id16_map_t *)id16_map_hndl;
+
+ ASSERT(id16_map->stack_idx >= -1);
+ ASSERT(id16_map->stack_idx < (int)id16_map->total);
+
+ if (id16_map->start == ID16_UNDEFINED)
+ goto done;
+
+ for (idx = 0; idx <= id16_map->stack_idx; idx++) {
+ ASSERT(id16_map->stack[idx] >= id16_map->start);
+ ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->dbg) {
+ uint16 val16 = id16_map->stack[idx];
+ if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
+ insane |= 1;
+ ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
+ OSL_OBFUSATE_BUF(id16_map_hndl), idx, val16));
+ }
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+ }
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->dbg) {
+ uint16 avail = 0; /* Audit available ids counts */
+ for (idx = 0; idx < id16_map_dbg->total; idx++) {
+ if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
+ avail++;
+ }
+ if (avail && (avail != (id16_map->stack_idx + 1))) {
+ insane |= 1;
+ ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
+ OSL_OBFUSCATE_BUF(id16_map_hndl),
+ avail, id16_map->stack_idx));
+ }
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+done:
+ /* invoke any other system audits */
+ return (!!insane);
+}
+/* END: Simple id16 allocator */
+
+void
+dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
+{
+ uint32 memsize;
+ memsize = sizeof(dll_pool_t) + (elems_max * elem_size);
+ if (pool)
+ MFREE(osh, pool, memsize);
+}
+dll_pool_t *
+dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size)
+{
+ uint32 memsize, i;
+ dll_pool_t * dll_pool_p;
+ dll_t * elem_p;
+
+ ASSERT(elem_size > sizeof(dll_t));
+
+ memsize = sizeof(dll_pool_t) + (elems_max * elem_size);
+
+ if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, memsize)) == NULL) {
+ printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
+ elems_max, elem_size);
+ ASSERT(0);
+ return dll_pool_p;
+ }
+
+ dll_init(&dll_pool_p->free_list);
+ dll_pool_p->elems_max = elems_max;
+ dll_pool_p->elem_size = elem_size;
+
+ elem_p = dll_pool_p->elements;
+ for (i = 0; i < elems_max; i++) {
+ dll_append(&dll_pool_p->free_list, elem_p);
+ elem_p = (dll_t *)((uintptr)elem_p + elem_size);
+ }
+
+ dll_pool_p->free_count = elems_max;
+
+ return dll_pool_p;
+}
+
+void *
+dll_pool_alloc(dll_pool_t * dll_pool_p)
+{
+ dll_t * elem_p;
+
+ if (dll_pool_p->free_count == 0) {
+ ASSERT(dll_empty(&dll_pool_p->free_list));
+ return NULL;
+ }
+
+ elem_p = dll_head_p(&dll_pool_p->free_list);
+ dll_delete(elem_p);
+ dll_pool_p->free_count -= 1;
+
+ return (void *)elem_p;
+}
+
+void
+dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p)
+{
+ dll_t * node_p = (dll_t *)elem_p;
+ dll_prepend(&dll_pool_p->free_list, node_p);
+ dll_pool_p->free_count += 1;
+}
+
+void
+dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
+{
+ dll_t * node_p = (dll_t *)elem_p;
+ dll_append(&dll_pool_p->free_list, node_p);
+ dll_pool_p->free_count += 1;
+}
+
+#endif // endif
+
#endif /* BCMDRIVER */
+
+#if defined(BCMDRIVER) || defined(WL_UNITTEST)
+
+/* triggers bcm_bprintf to print to kernel log */
+bool bcm_bprintf_bypass = FALSE;
+
+/* Initialization of bcmstrbuf structure */
+void
+bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
+{
+ b->origsize = b->size = size;
+ b->origbuf = b->buf = buf;
+ if (size > 0) {
+ buf[0] = '\0';
+ }
+}
+
+/* Buffer sprintf wrapper to guard against buffer overflow */
+int
+bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+
+ r = vsnprintf(b->buf, b->size, fmt, ap);
+ if (bcm_bprintf_bypass == TRUE) {
+ printf("%s", b->buf);
+ goto exit;
+ }
+
+ /* Non Ansi C99 compliant returns -1,
+ * Ansi compliant return r >= b->size,
+ * bcmstdlib returns 0, handle all
+ */
+ /* r == 0 is also the case when strlen(fmt) is zero.
+ * typically the case when "" is passed as argument.
+ */
+ if ((r == -1) || (r >= (int)b->size)) {
+ b->size = 0;
+ } else {
+ b->size -= (uint)r;
+ b->buf += r;
+ }
+
+exit:
+ va_end(ap);
+
+ return r;
+}
+
+void
+bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len)
+{
+ int i;
+
+ if (msg != NULL && msg[0] != '\0')
+ bcm_bprintf(b, "%s", msg);
+ for (i = 0; i < len; i ++)
+ bcm_bprintf(b, "%02X", buf[i]);
+ if (newline)
+ bcm_bprintf(b, "\n");
+}
+
+void
+bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
+{
+ int i;
+
+ for (i = 0; i < num_bytes; i++) {
+ num[i] += amount;
+ if (num[i] >= amount)
+ break;
+ amount = 1;
+ }
+}
+
+int
+bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
+{
+ int i;
+
+ for (i = nbytes - 1; i >= 0; i--) {
+ if (arg1[i] != arg2[i])
+ return (arg1[i] - arg2[i]);
+ }
+ return 0;
+}
+
+void
+bcm_print_bytes(const char *name, const uchar *data, int len)
+{
+ int i;
+ int per_line = 0;
+
+ printf("%s: %d \n", name ? name : "", len);
+ for (i = 0; i < len; i++) {
+ printf("%02x ", *data++);
+ per_line++;
+ if (per_line == 16) {
+ per_line = 0;
+ printf("\n");
+ }
+ }
+ printf("\n");
+}
+
+/* Look for vendor-specific IE with specified OUI and optional type */
+bcm_tlv_t *
+bcm_find_vendor_ie(const void *tlvs, uint tlvs_len, const char *voui, uint8 *type, uint type_len)
+{
+ const bcm_tlv_t *ie;
+ uint8 ie_len;
+
+ ie = (const bcm_tlv_t*)tlvs;
+
+ /* make sure we are looking at a valid IE */
+ if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
+ return NULL;
+ }
+
+ /* Walk through the IEs looking for an OUI match */
+ do {
+ ie_len = ie->len;
+ if ((ie->id == DOT11_MNG_VS_ID) &&
+ (ie_len >= (DOT11_OUI_LEN + type_len)) &&
+ !bcmp(ie->data, voui, DOT11_OUI_LEN))
+ {
+ /* compare optional type */
+ if (type_len == 0 ||
+ !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+ return (bcm_tlv_t *)(ie); /* a match */
+ GCC_DIAGNOSTIC_POP();
+ }
+ }
+ } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
+
+ return NULL;
+}
+
+#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
+ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
+#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
+
+int
+bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
+{
+ uint i, c;
+ char *p = buf;
+ char *endp = buf + SSID_FMT_BUF_LEN;
+
+ if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
+
+ for (i = 0; i < ssid_len; i++) {
+ c = (uint)ssid[i];
+ if (c == '\\') {
+ *p++ = '\\';
+ *p++ = '\\';
+ } else if (bcm_isprint((uchar)c)) {
+ *p++ = (char)c;
+ } else {
+ p += snprintf(p, (size_t)(endp - p), "\\x%02X", c);
+ }
+ }
+ *p = '\0';
+ ASSERT(p < endp);
+
+ return (int)(p - buf);
+}
+#endif // endif
+
+#endif /* BCMDRIVER || WL_UNITTEST */
+
+char *
+bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
+{
+ static const char hex[] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+ const uint8 *octet = ea->octet;
+ char *p = buf;
+ int i;
+
+ for (i = 0; i < 6; i++, octet++) {
+ *p++ = hex[(*octet >> 4) & 0xf];
+ *p++ = hex[*octet & 0xf];
+ *p++ = ':';
+ }
+
+ *(p-1) = '\0';
+
+ return (buf);
+}
+
+/* Find the position of first bit set
+ * in the given number.
+ */
+int
+bcm_find_fsb(uint32 num)
+{
+ uint8 pos = 0;
+ if (!num)
+ return pos;
+ while (!(num & 1)) {
+ num >>= 1;
+ pos++;
+ }
+ return (pos+1);
+}
+
+char *
+bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
+{
+ snprintf(buf, 16, "%d.%d.%d.%d",
+ ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
+ return (buf);
+}
+
+char *
+bcm_ipv6_ntoa(void *ipv6, char *buf)
+{
+ /* Implementing RFC 5952 Sections 4 + 5 */
+ /* Not thoroughly tested */
+ uint16 tmp[8];
+ uint16 *a = &tmp[0];
+ char *p = buf;
+ int i, i_max = -1, cnt = 0, cnt_max = 1;
+ uint8 *a4 = NULL;
+ memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
+
+ for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
+ if (a[i]) {
+ if (cnt > cnt_max) {
+ cnt_max = cnt;
+ i_max = i - cnt;
+ }
+ cnt = 0;
+ } else
+ cnt++;
+ }
+ if (cnt > cnt_max) {
+ cnt_max = cnt;
+ i_max = i - cnt;
+ }
+ if (i_max == 0 &&
+ /* IPv4-translated: ::ffff:0:a.b.c.d */
+ ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
+ /* IPv4-mapped: ::ffff:a.b.c.d */
+ (cnt_max == 5 && a[5] == 0xffff)))
+ a4 = (uint8*) (a + 6);
+
+ for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
+ if ((uint8*) (a + i) == a4) {
+ snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
+ break;
+ } else if (i == i_max) {
+ *p++ = ':';
+ i += cnt_max - 1;
+ p[0] = ':';
+ p[1] = '\0';
+ } else {
+ if (i)
+ *p++ = ':';
+ p += snprintf(p, 8, "%x", ntoh16(a[i]));
+ }
+ }
+
+ return buf;
+}
#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
const unsigned char bcm_ctype[] = {
@@ -298,10 +1732,10 @@
_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
};
-ulong
-bcm_strtoul(const char *cp, char **endp, uint base)
+uint64
+bcm_strtoull(const char *cp, char **endp, uint base)
{
- ulong result, last_result = 0, value;
+ uint64 result, last_result = 0, value;
bool minus;
minus = FALSE;
@@ -334,11 +1768,19 @@
result = 0;
while (bcm_isxdigit(*cp) &&
- (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
+ (value = (uint64)(bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10)) < base) {
result = result*base + value;
/* Detected overflow */
- if (result < last_result && !minus)
+ if (result < last_result && !minus) {
+ if (endp) {
+ /* Go to the end of current number */
+ while (bcm_isxdigit(*cp)) {
+ cp++;
+ }
+ *endp = DISCARD_QUAL(cp, char);
+ }
return (ulong)-1;
+ }
last_result = result;
cp++;
}
@@ -350,6 +1792,12 @@
*endp = DISCARD_QUAL(cp, char);
return (result);
+}
+
+ulong
+bcm_strtoul(const char *cp, char **endp, uint base)
+{
+ return (ulong) bcm_strtoull(cp, endp, base);
}
int
@@ -372,7 +1820,7 @@
len = (int)strlen(haystack) - nlen + 1;
for (i = 0; i < len; i++)
- if (memcmp(needle, &haystack[i], nlen) == 0)
+ if (memcmp(needle, &haystack[i], (size_t)nlen) == 0)
return DISCARD_QUAL(&haystack[i], char);
return (NULL);
}
@@ -414,7 +1862,6 @@
return (dest);
}
-
/****************************************************************************
* Function: bcmstrtok
@@ -477,7 +1924,7 @@
for (; *str; str++) {
if (map[*str >> 5] & (1 << (*str & 31))) {
if (tokdelim != NULL) {
- *tokdelim = *str;
+ *tokdelim = (char)*str;
}
*str++ = '\0';
@@ -496,10 +1943,8 @@
}
}
-
#define xToLower(C) \
((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
-
/****************************************************************************
* Function: bcmstricmp
@@ -531,7 +1976,6 @@
if (!*s1 && *s2) return -1;
return 0;
}
-
/****************************************************************************
* Function: bcmstrnicmp
@@ -576,7 +2020,7 @@
char *ep;
for (;;) {
- ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
+ ea->octet[i++] = (uint8) bcm_strtoul(p, &ep, 16);
p = ep;
if (!*p++ || i == 6)
break;
@@ -600,7 +2044,6 @@
return (i == IPV4_ADDR_LEN);
}
#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
-
#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
/* registry routine buffer preparation utility functions:
@@ -630,460 +2073,6 @@
return copyct;
}
#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
-
-char *
-bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
-{
- static const char hex[] =
- {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
- };
- const uint8 *octet = ea->octet;
- char *p = buf;
- int i;
-
- for (i = 0; i < 6; i++, octet++) {
- *p++ = hex[(*octet >> 4) & 0xf];
- *p++ = hex[*octet & 0xf];
- *p++ = ':';
- }
-
- *(p-1) = '\0';
-
- return (buf);
-}
-
-char *
-bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
-{
- snprintf(buf, 16, "%d.%d.%d.%d",
- ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
- return (buf);
-}
-
-char *
-bcm_ipv6_ntoa(void *ipv6, char *buf)
-{
- /* Implementing RFC 5952 Sections 4 + 5 */
- /* Not thoroughly tested */
- uint16 tmp[8];
- uint16 *a = &tmp[0];
- char *p = buf;
- int i, i_max = -1, cnt = 0, cnt_max = 1;
- uint8 *a4 = NULL;
- memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
-
- for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
- if (a[i]) {
- if (cnt > cnt_max) {
- cnt_max = cnt;
- i_max = i - cnt;
- }
- cnt = 0;
- } else
- cnt++;
- }
- if (cnt > cnt_max) {
- cnt_max = cnt;
- i_max = i - cnt;
- }
- if (i_max == 0 &&
- /* IPv4-translated: ::ffff:0:a.b.c.d */
- ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
- /* IPv4-mapped: ::ffff:a.b.c.d */
- (cnt_max == 5 && a[5] == 0xffff)))
- a4 = (uint8*) (a + 6);
-
- for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
- if ((uint8*) (a + i) == a4) {
- snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
- break;
- } else if (i == i_max) {
- *p++ = ':';
- i += cnt_max - 1;
- p[0] = ':';
- p[1] = '\0';
- } else {
- if (i)
- *p++ = ':';
- p += snprintf(p, 8, "%x", ntoh16(a[i]));
- }
- }
-
- return buf;
-}
-#ifdef BCMDRIVER
-
-void
-bcm_mdelay(uint ms)
-{
- uint i;
-
- for (i = 0; i < ms; i++) {
- OSL_DELAY(1000);
- }
-}
-
-
-
-
-
-#if defined(DHD_DEBUG)
-/* pretty hex print a pkt buffer chain */
-void
-prpkt(const char *msg, osl_t *osh, void *p0)
-{
- void *p;
-
- if (msg && (msg[0] != '\0'))
- printf("%s:\n", msg);
-
- for (p = p0; p; p = PKTNEXT(osh, p))
- prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
-}
-#endif
-
-/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
- * Also updates the inplace vlan tag if requested.
- * For debugging, it returns an indication of what it did.
- */
-uint BCMFASTPATH
-pktsetprio(void *pkt, bool update_vtag)
-{
- struct ether_header *eh;
- struct ethervlan_header *evh;
- uint8 *pktdata;
- int priority = 0;
- int rc = 0;
-
- pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
- ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
-
- eh = (struct ether_header *) pktdata;
-
- if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
- uint16 vlan_tag;
- int vlan_prio, dscp_prio = 0;
-
- evh = (struct ethervlan_header *)eh;
-
- vlan_tag = ntoh16(evh->vlan_tag);
- vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
-
- if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
- (evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
- uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
- uint8 tos_tc = IP_TOS46(ip_body);
- dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
- }
-
- /* DSCP priority gets precedence over 802.1P (vlan tag) */
- if (dscp_prio != 0) {
- priority = dscp_prio;
- rc |= PKTPRIO_VDSCP;
- } else {
- priority = vlan_prio;
- rc |= PKTPRIO_VLAN;
- }
- /*
- * If the DSCP priority is not the same as the VLAN priority,
- * then overwrite the priority field in the vlan tag, with the
- * DSCP priority value. This is required for Linux APs because
- * the VLAN driver on Linux, overwrites the skb->priority field
- * with the priority value in the vlan tag
- */
- if (update_vtag && (priority != vlan_prio)) {
- vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
- vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
- evh->vlan_tag = hton16(vlan_tag);
- rc |= PKTPRIO_UPD;
- }
-#ifdef DHD_LOSSLESS_ROAMING
- } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
- priority = PRIO_8021D_NC;
- rc = PKTPRIO_DSCP;
-#endif /* DHD_LOSSLESS_ROAMING */
- } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
- (eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
- uint8 *ip_body = pktdata + sizeof(struct ether_header);
- uint8 tos_tc = IP_TOS46(ip_body);
- uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
- switch (dscp) {
- case DSCP_EF:
- priority = PRIO_8021D_VO;
- break;
- case DSCP_AF31:
- case DSCP_AF32:
- case DSCP_AF33:
- priority = PRIO_8021D_CL;
- break;
- case DSCP_AF21:
- case DSCP_AF22:
- case DSCP_AF23:
- case DSCP_AF11:
- case DSCP_AF12:
- case DSCP_AF13:
- priority = PRIO_8021D_EE;
- break;
- default:
- priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
- break;
- }
-
- rc |= PKTPRIO_DSCP;
- }
-
- ASSERT(priority >= 0 && priority <= MAXPRIO);
- PKTSETPRIO(pkt, priority);
- return (rc | priority);
-}
-
-/* lookup user priority for specified DSCP */
-static uint8
-dscp2up(uint8 *up_table, uint8 dscp)
-{
- uint8 user_priority = 255;
-
- /* lookup up from table if parameters valid */
- if (up_table != NULL && dscp < UP_TABLE_MAX) {
- user_priority = up_table[dscp];
- }
-
- /* 255 is unused value so return up from dscp */
- if (user_priority == 255) {
- user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
- }
-
- return user_priority;
-}
-
-/* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
-uint BCMFASTPATH
-pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag)
-{
- if (up_table) {
- uint8 *pktdata;
- uint pktlen;
- uint8 dscp;
- uint user_priority = 0;
- uint rc = 0;
-
- pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
- pktlen = PKTLEN(OSH_NULL, pkt);
-
- if (pktgetdscp(pktdata, pktlen, &dscp)) {
- rc = PKTPRIO_DSCP;
- user_priority = dscp2up(up_table, dscp);
- PKTSETPRIO(pkt, user_priority);
- }
-
- return (rc | user_priority);
- } else {
- return pktsetprio(pkt, update_vtag);
- }
-}
-
-/* Returns TRUE and DSCP if IP header found, FALSE otherwise.
- */
-bool BCMFASTPATH
-pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
-{
- struct ether_header *eh;
- struct ethervlan_header *evh;
- uint8 *ip_body;
- bool rc = FALSE;
-
- /* minimum length is ether header and IP header */
- if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
- return FALSE;
-
- eh = (struct ether_header *) pktdata;
-
- if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
- ip_body = pktdata + sizeof(struct ether_header);
- *dscp = IP_DSCP46(ip_body);
- rc = TRUE;
- }
- else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
- evh = (struct ethervlan_header *)eh;
-
- /* minimum length is ethervlan header and IP header */
- if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
- evh->ether_type == HTON16(ETHER_TYPE_IP)) {
- ip_body = pktdata + sizeof(struct ethervlan_header);
- *dscp = IP_DSCP46(ip_body);
- rc = TRUE;
- }
- }
-
- return rc;
-}
-
-/* usr_prio range from low to high with usr_prio value */
-static bool
-up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high)
-{
- int i;
-
- if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) {
- return FALSE;
- }
-
- for (i = low; i <= high; i++) {
- up_table[i] = usr_prio;
- }
-
- return TRUE;
-}
-
-/* set user priority table */
-int BCMFASTPATH
-wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie)
-{
- uint8 len;
-
- if (up_table == NULL || qos_map_ie == NULL) {
- return BCME_ERROR;
- }
-
- /* clear table to check table was set or not */
- memset(up_table, 0xff, UP_TABLE_MAX);
-
- /* length of QoS Map IE must be 16+n*2, n is number of exceptions */
- if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID &&
- (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH &&
- (len % 2) == 0) {
- uint8 *except_ptr = (uint8 *)qos_map_ie->data;
- uint8 except_len = len - QOS_MAP_FIXED_LENGTH;
- uint8 *range_ptr = except_ptr + except_len;
- int i;
-
- /* fill in ranges */
- for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) {
- uint8 low = range_ptr[i];
- uint8 high = range_ptr[i + 1];
- if (low == 255 && high == 255) {
- continue;
- }
-
- if (!up_table_set(up_table, i / 2, low, high)) {
- /* clear the table on failure */
- memset(up_table, 0xff, UP_TABLE_MAX);
- return BCME_ERROR;
- }
- }
-
- /* update exceptions */
- for (i = 0; i < except_len; i += 2) {
- uint8 dscp = except_ptr[i];
- uint8 usr_prio = except_ptr[i+1];
-
- /* exceptions with invalid dscp/usr_prio are ignored */
- up_table_set(up_table, usr_prio, dscp, dscp);
- }
- }
-
- return BCME_OK;
-}
-
-/* The 0.5KB string table is not removed by compiler even though it's unused */
-
-static char bcm_undeferrstr[32];
-static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
-
-/* Convert the error codes into related error strings */
-const char *
-bcmerrorstr(int bcmerror)
-{
- /* check if someone added a bcmerror code but forgot to add errorstring */
- ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
-
- if (bcmerror > 0 || bcmerror < BCME_LAST) {
- snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
- return bcm_undeferrstr;
- }
-
- ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
-
- return bcmerrorstrtable[-bcmerror];
-}
-
-
-
-/* iovar table lookup */
-/* could mandate sorted tables and do a binary search */
-const bcm_iovar_t*
-bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
-{
- const bcm_iovar_t *vi;
- const char *lookup_name;
-
- /* skip any ':' delimited option prefixes */
- lookup_name = strrchr(name, ':');
- if (lookup_name != NULL)
- lookup_name++;
- else
- lookup_name = name;
-
- ASSERT(table != NULL);
-
- for (vi = table; vi->name; vi++) {
- if (!strcmp(vi->name, lookup_name))
- return vi;
- }
- /* ran to end of table */
-
- return NULL; /* var name not found */
-}
-
-int
-bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
-{
- int bcmerror = 0;
-
- /* length check on io buf */
- switch (vi->type) {
- case IOVT_BOOL:
- case IOVT_INT8:
- case IOVT_INT16:
- case IOVT_INT32:
- case IOVT_UINT8:
- case IOVT_UINT16:
- case IOVT_UINT32:
- /* all integers are int32 sized args at the ioctl interface */
- if (len < (int)sizeof(int)) {
- bcmerror = BCME_BUFTOOSHORT;
- }
- break;
-
- case IOVT_BUFFER:
- /* buffer must meet minimum length requirement */
- if (len < vi->minlen) {
- bcmerror = BCME_BUFTOOSHORT;
- }
- break;
-
- case IOVT_VOID:
- if (!set) {
- /* Cannot return nil... */
- bcmerror = BCME_UNSUPPORTED;
- } else if (len) {
- /* Set is an action w/o parameters */
- bcmerror = BCME_BUFTOOLONG;
- }
- break;
-
- default:
- /* unknown type for length check in iovar info */
- ASSERT(0);
- bcmerror = BCME_UNSUPPORTED;
- }
-
- return bcmerror;
-}
-
-#endif /* BCMDRIVER */
#ifdef BCM_OBJECT_TRACE
@@ -1522,22 +2511,70 @@
((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
((data != NULL) || (datalen == 0))) {
- /* write type, len fields */
+ /* write type, len fields */
dst_tlv->id = (uint8)type;
- dst_tlv->len = (uint8)datalen;
+ dst_tlv->len = (uint8)datalen;
/* if data is present, copy to the output buffer and update
* pointer to output buffer
*/
if (datalen > 0) {
- memcpy(dst_tlv->data, data, datalen);
+ memcpy(dst_tlv->data, data, (size_t)datalen);
}
/* update the output destination poitner to point past
* the TLV written
*/
new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
+ }
+
+ return (new_dst);
+}
+
+uint8 *
+bcm_write_tlv_ext(uint8 type, uint8 ext, const void *data, uint8 datalen, uint8 *dst)
+{
+ uint8 *new_dst = dst;
+ bcm_tlv_ext_t *dst_tlv = (bcm_tlv_ext_t *)dst;
+
+ /* dst buffer should always be valid */
+ ASSERT(dst);
+
+ /* data len must be within valid range */
+ ASSERT(datalen <= BCM_TLV_EXT_MAX_DATA_SIZE);
+
+ /* source data buffer pointer should be valid, unless datalen is 0
+ * meaning no data with this TLV
+ */
+ ASSERT((data != NULL) || (datalen == 0));
+
+ /* only do work if the inputs are valid
+ * - must have a dst to write to AND
+ * - datalen must be within range AND
+ * - the source data pointer must be non-NULL if datalen is non-zero
+ * (this last condition detects datalen > 0 with a NULL data pointer)
+ */
+ if ((dst != NULL) &&
+ (datalen <= BCM_TLV_EXT_MAX_DATA_SIZE) &&
+ ((data != NULL) || (datalen == 0))) {
+
+ /* write type, len fields */
+ dst_tlv->id = (uint8)type;
+ dst_tlv->ext = ext;
+ dst_tlv->len = 1 + (uint8)datalen;
+
+ /* if data is present, copy to the output buffer and update
+ * pointer to output buffer
+ */
+ if (datalen > 0) {
+ memcpy(dst_tlv->data, data, datalen);
+ }
+
+ /* update the output destination poitner to point past
+ * the TLV written
+ */
+ new_dst = dst + BCM_TLV_EXT_HDR_SIZE + datalen;
}
return (new_dst);
@@ -1553,7 +2590,7 @@
/* if len + tlv hdr len is more than destlen, don't do anything
* just return the buffer untouched
*/
- if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) {
+ if ((int)(datalen + (int)BCM_TLV_HDR_SIZE) <= dst_maxlen) {
new_dst = bcm_write_tlv(type, data, datalen, dst);
}
@@ -1580,7 +2617,6 @@
return (new_dst);
}
-
uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen)
{
uint8 *new_dst = dst;
@@ -1595,7 +2631,6 @@
return (new_dst);
}
-
#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
/*******************************************************************************
@@ -1660,7 +2695,7 @@
uint8
hndcrc8(
- uint8 *pdata, /* pointer to array of data to process */
+ const uint8 *pdata, /* pointer to array of data to process */
uint nbytes, /* number of input data bytes to process */
uint8 crc /* either CRC8_INIT_VALUE or previous return value */
)
@@ -1733,7 +2768,7 @@
uint16
hndcrc16(
- uint8 *pdata, /* pointer to array of data to process */
+ const uint8 *pdata, /* pointer to array of data to process */
uint nbytes, /* number of input data bytes to process */
uint16 crc /* either CRC16_INIT_VALUE or previous return value */
)
@@ -1815,9 +2850,9 @@
* accumulating over multiple pieces.
*/
uint32
-hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
+hndcrc32(const uint8 *pdata, uint nbytes, uint32 crc)
{
- uint8 *pend;
+ const uint8 *pend;
pend = pdata + nbytes;
while (pdata < pend)
CRC_INNER_LOOP(32, crc, *pdata++);
@@ -1826,8 +2861,8 @@
}
#ifdef notdef
-#define CLEN 1499 /* CRC Length */
-#define CBUFSIZ (CLEN+4)
+#define CLEN 1499 /* CRC Length */
+#define CBUFSIZ (CLEN+4)
#define CNBUFS 5 /* # of bufs */
void
@@ -1870,9 +2905,9 @@
* by the TLV parameter's length if it is valid.
*/
bcm_tlv_t *
-bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
+bcm_next_tlv(const bcm_tlv_t *elt, uint *buflen)
{
- int len;
+ uint len;
/* validate current elt */
if (!bcm_valid_tlv(elt, *buflen)) {
@@ -1881,7 +2916,7 @@
/* advance to next elt */
len = elt->len;
- elt = (bcm_tlv_t*)(elt->data + len);
+ elt = (const bcm_tlv_t*)(elt->data + len);
*buflen -= (TLV_HDR_LEN + len);
/* validate next elt */
@@ -1889,7 +2924,112 @@
return NULL;
}
- return elt;
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+ return (bcm_tlv_t *)(elt);
+ GCC_DIAGNOSTIC_POP();
+}
+
+/**
+ * Advance a const tlv buffer pointer and length up to the given tlv element pointer
+ * 'elt'. The function checks that elt is a valid tlv; the elt pointer and data
+ * are all in the range of the buffer/length.
+ *
+ * @param elt pointer to a valid bcm_tlv_t in the buffer
+ * @param buffer pointer to a tlv buffer
+ * @param buflen length of the buffer in bytes
+ *
+ * On return, if elt is not a tlv in the buffer bounds, the *buffer parameter
+ * will be set to NULL and *buflen parameter will be set to zero. Otherwise,
+ * *buffer will point to elt, and *buflen will have been adjusted by the the
+ * difference between *buffer and elt.
+ */
+void
+bcm_tlv_buffer_advance_to(const bcm_tlv_t *elt, const uint8 **buffer, uint *buflen)
+{
+ uint new_buflen;
+ const uint8 *new_buffer;
+
+ new_buffer = (const uint8*)elt;
+
+ /* make sure the input buffer pointer is non-null, that (buffer + buflen) does not wrap,
+ * and that the elt pointer is in the range of [buffer, buffer + buflen]
+ */
+ if ((*buffer != NULL) &&
+ ((uintptr)*buffer < ((uintptr)*buffer + *buflen)) &&
+ (new_buffer >= *buffer) &&
+ (new_buffer < (*buffer + *buflen))) {
+ /* delta between buffer and new_buffer is <= *buflen, so truncating cast to uint
+ * from ptrdiff is ok
+ */
+ uint delta = (uint)(new_buffer - *buffer);
+
+ /* New buffer length is old len minus the delta from the buffer start to elt.
+ * The check just above guarantees that the subtractions does not underflow.
+ */
+ new_buflen = *buflen - delta;
+
+ /* validate current elt */
+ if (bcm_valid_tlv(elt, new_buflen)) {
+ /* All good, so update the input/output parameters */
+ *buffer = new_buffer;
+ *buflen = new_buflen;
+ return;
+ }
+ }
+
+ /* something did not check out, clear out the buffer info */
+ *buffer = NULL;
+ *buflen = 0;
+
+ return;
+}
+
+/**
+ * Advance a const tlv buffer pointer and length past the given tlv element pointer
+ * 'elt'. The function checks that elt is a valid tlv; the elt pointer and data
+ * are all in the range of the buffer/length. The function also checks that the
+ * remaining buffer starts with a valid tlv.
+ *
+ * @param elt pointer to a valid bcm_tlv_t in the buffer
+ * @param buffer pointer to a tlv buffer
+ * @param buflen length of the buffer in bytes
+ *
+ * On return, if elt is not a tlv in the buffer bounds, or the remaining buffer
+ * following the elt does not begin with a tlv in the buffer bounds, the *buffer
+ * parameter will be set to NULL and *buflen parameter will be set to zero.
+ * Otherwise, *buffer will point to the first byte past elt, and *buflen will
+ * have the remaining buffer length.
+ */
+void
+bcm_tlv_buffer_advance_past(const bcm_tlv_t *elt, const uint8 **buffer, uint *buflen)
+{
+ /* Start by advancing the buffer up to the given elt */
+ bcm_tlv_buffer_advance_to(elt, buffer, buflen);
+
+ /* if that did not work, bail out */
+ if (*buflen == 0) {
+ return;
+ }
+
+#if defined(__COVERITY__)
+ /* The elt has been verified by bcm_tlv_buffer_advance_to() to be a valid element,
+ * so its elt->len is in the bounds of the buffer. The following check prevents
+ * Coverity from flagging the (elt->data + elt->len) statement below as using a
+ * tainted elt->len to index into array 'elt->data'.
+ */
+ if (elt->len > *buflen) {
+ return;
+ }
+#endif /* __COVERITY__ */
+
+ /* We know we are advanced up to a good tlv.
+ * Now just advance to the following tlv.
+ */
+ elt = (const bcm_tlv_t*)(elt->data + elt->len);
+
+ bcm_tlv_buffer_advance_to(elt, buffer, buflen);
+
+ return;
}
/*
@@ -1898,25 +3038,68 @@
* matches tag
*/
bcm_tlv_t *
-bcm_parse_tlvs(void *buf, int buflen, uint key)
+bcm_parse_tlvs(const void *buf, uint buflen, uint key)
+{
+ const bcm_tlv_t *elt;
+ int totlen;
+
+ if ((elt = (const bcm_tlv_t*)buf) == NULL) {
+ return NULL;
+ }
+ totlen = (int)buflen;
+
+ /* find tagged parameter */
+ while (totlen >= TLV_HDR_LEN) {
+ uint len = elt->len;
+
+ /* validate remaining totlen */
+ if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+ return (bcm_tlv_t *)(elt);
+ GCC_DIAGNOSTIC_POP();
+ }
+
+ elt = (const bcm_tlv_t*)((const uint8*)elt + (len + TLV_HDR_LEN));
+ totlen -= (len + TLV_HDR_LEN);
+ }
+
+ return NULL;
+}
+
+bcm_tlv_t *
+bcm_parse_tlvs_dot11(const void *buf, int buflen, uint key, bool id_ext)
{
bcm_tlv_t *elt;
int totlen;
- if ((elt = (bcm_tlv_t*)buf) == NULL) {
- return NULL;
- }
+ /*
+ ideally, we don't want to do that, but returning a const pointer
+ from these parse function spreads casting everywhere in the code
+ */
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+ elt = (bcm_tlv_t*)buf;
+ GCC_DIAGNOSTIC_POP();
+
totlen = buflen;
/* find tagged parameter */
while (totlen >= TLV_HDR_LEN) {
int len = elt->len;
- /* validate remaining totlen */
- if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
+ do {
+ /* validate remaining totlen */
+ if (totlen < (int)(len + TLV_HDR_LEN))
+ break;
- return (elt);
- }
+ if (id_ext) {
+ if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key))
+ break;
+ } else if (elt->id != key) {
+ break;
+ }
+
+ return (bcm_tlv_t *)(elt); /* a match */
+ } while (0);
elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
totlen -= (len + TLV_HDR_LEN);
@@ -1932,9 +3115,10 @@
* return NULL if not found or length field < min_varlen
*/
bcm_tlv_t *
-bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen)
+bcm_parse_tlvs_min_bodylen(const void *buf, int buflen, uint key, int min_bodylen)
{
- bcm_tlv_t * ret = bcm_parse_tlvs(buf, buflen, key);
+ bcm_tlv_t * ret;
+ ret = bcm_parse_tlvs(buf, (uint)buflen, key);
if (ret == NULL || ret->len < min_bodylen) {
return NULL;
}
@@ -1947,13 +3131,13 @@
* matches tag. Stop parsing when we see an element whose ID is greater
* than the target key.
*/
-bcm_tlv_t *
-bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
+const bcm_tlv_t *
+bcm_parse_ordered_tlvs(const void *buf, int buflen, uint key)
{
- bcm_tlv_t *elt;
+ const bcm_tlv_t *elt;
int totlen;
- elt = (bcm_tlv_t*)buf;
+ elt = (const bcm_tlv_t*)buf;
totlen = buflen;
/* find tagged parameter */
@@ -1971,7 +3155,7 @@
return (elt);
}
- elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
+ elt = (const bcm_tlv_t*)((const uint8*)elt + (len + TLV_HDR_LEN));
totlen -= (len + TLV_HDR_LEN);
}
return NULL;
@@ -1996,8 +3180,8 @@
bit = bd->bitfield[i].bit;
if ((flags & mask) == bit) {
if (len > (int)strlen(name)) {
- slen = strlen(name);
- strncpy(buf, name, slen+1);
+ slen = (int)strlen(name);
+ strncpy(buf, name, (size_t)slen+1);
}
break;
}
@@ -2031,7 +3215,7 @@
} else if ((flags & bit) == 0)
continue;
flags &= ~bit;
- nlen = strlen(name);
+ nlen = (int)strlen(name);
slen += nlen;
/* count btwn flag space */
if (flags != 0)
@@ -2040,7 +3224,7 @@
if (len <= slen)
break;
/* copy NULL char but don't count it */
- strncpy(p, name, nlen + 1);
+ strncpy(p, name, (size_t)nlen + 1);
p += nlen;
/* copy btwn flag space and NULL char */
if (flags != 0)
@@ -2054,7 +3238,58 @@
return (int)(p - buf);
}
-#endif
+
+/* print out whcih bits in octet array 'addr' are set. bcm_bit_desc_t:bit is a bit offset. */
+int
+bcm_format_octets(const bcm_bit_desc_t *bd, uint bdsz,
+ const uint8 *addr, uint size, char *buf, int len)
+{
+ uint i;
+ char *p = buf;
+ int slen = 0, nlen = 0;
+ uint32 bit;
+ const char* name;
+ bool more = FALSE;
+
+ BCM_REFERENCE(size);
+
+ if (len < 2 || !buf)
+ return 0;
+
+ buf[0] = '\0';
+
+ for (i = 0; i < bdsz; i++) {
+ bit = bd[i].bit;
+ name = bd[i].name;
+ CLANG_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+ if (isset(addr, bit)) {
+ CLANG_DIAGNOSTIC_POP();
+ nlen = (int)strlen(name);
+ slen += nlen;
+ /* need SPACE - for simplicity */
+ slen += 1;
+ /* need NULL as well */
+ if (len < slen + 1) {
+ more = TRUE;
+ break;
+ }
+ memcpy(p, name, (size_t)nlen);
+ p += nlen;
+ p[0] = ' ';
+ p += 1;
+ p[0] = '\0';
+ }
+ }
+
+ if (more) {
+ p[0] = '>';
+ p += 1;
+ p[0] = '\0';
+ }
+
+ return (int)(p - buf);
+}
+#endif // endif
/* print bytes formatted as hex to a string. return the resulting string length */
int
@@ -2073,7 +3308,7 @@
/* pretty hex print a contiguous buffer */
void
-prhex(const char *msg, uchar *buf, uint nbytes)
+prhex(const char *msg, const uchar *buf, uint nbytes)
{
char line[128], *p;
int len = sizeof(line);
@@ -2086,12 +3321,12 @@
p = line;
for (i = 0; i < nbytes; i++) {
if (i % 16 == 0) {
- nchar = snprintf(p, len, " %04x: ", i); /* line prefix */
+ nchar = snprintf(p, (size_t)len, " %04x: ", i); /* line prefix */
p += nchar;
len -= nchar;
}
if (len > 0) {
- nchar = snprintf(p, len, "%02x ", buf[i]);
+ nchar = snprintf(p, (size_t)len, "%02x ", buf[i]);
p += nchar;
len -= nchar;
}
@@ -2116,11 +3351,22 @@
"AES_CCM",
"AES_OCB_MSDU",
"AES_OCB_MPDU",
+#ifdef BCMCCX
+ "CKIP",
+ "CKIP_MMH",
+ "WEP_MMH",
+ "NALG",
+#else
"NALG",
"UNDEF",
"UNDEF",
"UNDEF",
+#endif /* BCMCCX */
+#ifdef BCMWAPI_WAI
"WAPI",
+#else
+ "UNDEF",
+#endif // endif
"PMK",
"BIP",
"AES_GCM",
@@ -2138,14 +3384,24 @@
return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
}
-
char *
bcm_chipname(uint chipid, char *buf, uint len)
{
const char *fmt;
fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
+ /*
+ * The following call to snprintf generates a compiler warning
+ * due to -Wformat-nonliteral. However, the format string is coming
+ * from internal callers rather than external data input, and is a
+ * useful debugging tool serving a variety of diagnostics. Rather
+ * than expand code size by replicating multiple functions with different
+ * argument lists, or disabling the warning globally, let's consider
+ * if we can just disable the warning for this one instance.
+ */
+ CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT()
snprintf(buf, len, fmt, chipid);
+ CLANG_DIAGNOSTIC_POP()
return buf;
}
@@ -2203,21 +3459,33 @@
while (bufsize > 1) {
if (cur_ptr->nameandfmt == NULL)
break;
+
+ /*
+ * The following call to snprintf generates a compiler warning
+ * due to -Wformat-nonliteral. However, the format string is coming
+ * from internal callers rather than external data input, and is a
+ * useful debugging tool serving a variety of diagnostics. Rather
+ * than expand code size by replicating multiple functions with different
+ * argument lists, or disabling the warning globally, let's consider
+ * if we can just disable the warning for this one instance.
+ */
+ CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT()
len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
- read_rtn(arg0, arg1, cur_ptr->offset));
+ read_rtn(arg0, arg1, cur_ptr->offset));
+ CLANG_DIAGNOSTIC_POP()
/* check for snprintf overflow or error */
if (len < 0 || (uint32)len >= bufsize)
- len = bufsize - 1;
+ len = (int)(bufsize - 1);
buf += len;
- bufsize -= len;
- filled_len += len;
+ bufsize -= (uint32)len;
+ filled_len += (uint32)len;
cur_ptr++;
}
return filled_len;
}
uint
-bcm_mkiovar(const char *name, char *data, uint datalen, char *buf, uint buflen)
+bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint buflen)
{
uint len;
@@ -2258,7 +3526,7 @@
#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
-/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
+/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
@@ -2288,7 +3556,7 @@
/* return the mW value scaled down to the correct factor of 10,
* adding in factor/2 to get proper rounding.
*/
- return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
+ return (uint16)((nqdBm_to_mW_map[idx] + factor/2) / factor);
}
uint8
@@ -2322,7 +3590,6 @@
return (qdbm);
}
-
uint
bcm_bitcount(uint8 *bitmap, uint length)
{
@@ -2337,175 +3604,6 @@
}
return bitcount;
}
-
-#if defined(BCMDRIVER) || defined(WL_UNITTEST)
-
-/* triggers bcm_bprintf to print to kernel log */
-bool bcm_bprintf_bypass = FALSE;
-
-/* Initialization of bcmstrbuf structure */
-void
-bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
-{
- b->origsize = b->size = size;
- b->origbuf = b->buf = buf;
-}
-
-/* Buffer sprintf wrapper to guard against buffer overflow */
-int
-bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
-{
- va_list ap;
- int r;
-
- va_start(ap, fmt);
-
- r = vsnprintf(b->buf, b->size, fmt, ap);
- if (bcm_bprintf_bypass == TRUE) {
- printf("%s\n", b->buf);
- goto exit;
- }
-
- /* Non Ansi C99 compliant returns -1,
- * Ansi compliant return r >= b->size,
- * bcmstdlib returns 0, handle all
- */
- /* r == 0 is also the case when strlen(fmt) is zero.
- * typically the case when "" is passed as argument.
- */
- if ((r == -1) || (r >= (int)b->size)) {
- b->size = 0;
- } else {
- b->size -= r;
- b->buf += r;
- }
-
-exit:
- va_end(ap);
-
- return r;
-}
-
-void
-bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len)
-{
- int i;
-
- if (msg != NULL && msg[0] != '\0')
- bcm_bprintf(b, "%s", msg);
- for (i = 0; i < len; i ++)
- bcm_bprintf(b, "%02X", buf[i]);
- if (newline)
- bcm_bprintf(b, "\n");
-}
-
-void
-bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
-{
- int i;
-
- for (i = 0; i < num_bytes; i++) {
- num[i] += amount;
- if (num[i] >= amount)
- break;
- amount = 1;
- }
-}
-
-int
-bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
-{
- int i;
-
- for (i = nbytes - 1; i >= 0; i--) {
- if (arg1[i] != arg2[i])
- return (arg1[i] - arg2[i]);
- }
- return 0;
-}
-
-void
-bcm_print_bytes(const char *name, const uchar *data, int len)
-{
- int i;
- int per_line = 0;
-
- printf("%s: %d \n", name ? name : "", len);
- for (i = 0; i < len; i++) {
- printf("%02x ", *data++);
- per_line++;
- if (per_line == 16) {
- per_line = 0;
- printf("\n");
- }
- }
- printf("\n");
-}
-
-/* Look for vendor-specific IE with specified OUI and optional type */
-bcm_tlv_t *
-bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len)
-{
- bcm_tlv_t *ie;
- uint8 ie_len;
-
- ie = (bcm_tlv_t*)tlvs;
-
- /* make sure we are looking at a valid IE */
- if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
- return NULL;
- }
-
- /* Walk through the IEs looking for an OUI match */
- do {
- ie_len = ie->len;
- if ((ie->id == DOT11_MNG_PROPR_ID) &&
- (ie_len >= (DOT11_OUI_LEN + type_len)) &&
- !bcmp(ie->data, voui, DOT11_OUI_LEN))
- {
- /* compare optional type */
- if (type_len == 0 ||
- !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
- return (ie); /* a match */
- }
- }
- } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
-
- return NULL;
-}
-
-#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
- defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
-#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
-
-int
-bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
-{
- uint i, c;
- char *p = buf;
- char *endp = buf + SSID_FMT_BUF_LEN;
-
- if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
-
- for (i = 0; i < ssid_len; i++) {
- c = (uint)ssid[i];
- if (c == '\\') {
- *p++ = '\\';
- *p++ = '\\';
- } else if (bcm_isprint((uchar)c)) {
- *p++ = (char)c;
- } else {
- p += snprintf(p, (endp - p), "\\x%02X", c);
- }
- }
- *p = '\0';
- ASSERT(p < endp);
-
- return (int)(p - buf);
-}
-#endif
-
-#endif /* BCMDRIVER || WL_UNITTEST */
/*
* ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
@@ -2560,64 +3658,6 @@
*dp++ = 0;
return buf_len;
-}
-
-/* calculate a * b + c */
-void
-bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
-{
-#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
- uint32 r1, r0;
- uint32 a1, a0, b1, b0, t, cc = 0;
-
- a1 = a >> 16;
- a0 = a & 0xffff;
- b1 = b >> 16;
- b0 = b & 0xffff;
-
- r0 = a0 * b0;
- FORMALIZE(r0);
-
- t = (a1 * b0) << 16;
- FORMALIZE(t);
-
- r0 += t;
- FORMALIZE(r0);
-
- t = (a0 * b1) << 16;
- FORMALIZE(t);
-
- r0 += t;
- FORMALIZE(r0);
-
- FORMALIZE(c);
-
- r0 += c;
- FORMALIZE(r0);
-
- r0 |= (cc % 2) ? 0x80000000 : 0;
- r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2);
-
- *r_high = r1;
- *r_low = r0;
-}
-
-/* calculate a / b */
-void
-bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
-{
- uint32 a1 = a_high, a0 = a_low, r0 = 0;
-
- if (b < 2)
- return;
-
- while (a1 != 0) {
- r0 += (0xffffffff / b) * a1;
- bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
- }
-
- r0 += a0 / b;
- *r = r0;
}
#ifndef setbit /* As in the header file */
@@ -2686,7 +3726,12 @@
{
int i;
for (i = NBITS(uint32) - 1; i >= 0; i--) {
- printf(isbitset(u32arg, i) ? "1" : "0");
+ if (isbitset(u32arg, i)) {
+ printf("1");
+ } else {
+ printf("0");
+ }
+
if ((i % NBBY) == 0) printf(" ");
}
printf("\n");
@@ -2697,13 +3742,13 @@
bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
{
while (len > 1) {
- sum += (buf[0] << 8) | buf[1];
+ sum += (uint32)((buf[0] << 8) | buf[1]);
buf += 2;
len -= 2;
}
if (len > 0) {
- sum += (*buf) << 8;
+ sum += (uint32)((*buf) << 8);
}
while (sum >> 16) {
@@ -2712,797 +3757,11 @@
return ((uint16)~sum);
}
-#if defined(BCMDRIVER) && !defined(_CFEZ_)
-/*
- * Hierarchical Multiword bitmap based small id allocator.
- *
- * Multilevel hierarchy bitmap. (maximum 2 levels)
- * First hierarchy uses a multiword bitmap to identify 32bit words in the
- * second hierarchy that have at least a single bit set. Each bit in a word of
- * the second hierarchy represents a unique ID that may be allocated.
- *
- * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
- * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
- * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
- * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
- * non-zero bitmap word carrying at least one free ID.
- * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
- * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
- *
- * Design Notes:
- * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
- * bits are computed each time on allocation and deallocation, requiring 4
- * array indexed access and 3 arithmetic operations. When not defined, a runtime
- * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
- * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
- * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
- * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
- *
- * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
- * size is fixed. No intention to support larger than 4K indice allocation. ID
- * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
- * with savings in not having to use an indirect access, had it been dynamically
- * allocated.
- */
-#define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */
-#define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
-#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
-#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
-#define BCM_MWBMAP_SHIFT_OP (5)
-#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
-#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
-#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
-
-/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
-#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
-#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
-
-#if defined(BCM_MWBMAP_DEBUG)
-#define BCM_MWBMAP_AUDIT(mwb) \
- do { \
- ASSERT((mwb != NULL) && \
- (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
- bcm_mwbmap_audit(mwb); \
- } while (0)
-#define MWBMAP_ASSERT(exp) ASSERT(exp)
-#define MWBMAP_DBG(x) printf x
-#else /* !BCM_MWBMAP_DEBUG */
-#define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
-#define MWBMAP_ASSERT(exp) do {} while (0)
-#define MWBMAP_DBG(x)
-#endif /* !BCM_MWBMAP_DEBUG */
-
-
-typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
- uint16 wmaps; /* Total number of words in free wd bitmap */
- uint16 imaps; /* Total number of words in free id bitmap */
- int32 ifree; /* Count of free indices. Used only in audits */
- uint16 total; /* Total indices managed by multiword bitmap */
-
- void * magic; /* Audit handle parameter from user */
-
- uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */
-#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
- int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */
-#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
-
- uint32 id_bitmap[0]; /* Second level bitmap */
-} bcm_mwbmap_t;
-
-/* Incarnate a hierarchical multiword bitmap based small index allocator. */
-struct bcm_mwbmap *
-bcm_mwbmap_init(osl_t *osh, uint32 items_max)
+int
+BCMRAMFN(valid_bcmerror)(int e)
{
- struct bcm_mwbmap * mwbmap_p;
- uint32 wordix, size, words, extra;
-
- /* Implementation Constraint: Uses 32bit word bitmap */
- MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
- MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
- MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
- MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
-
- ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
-
- /* Determine the number of words needed in the multiword bitmap */
- extra = BCM_MWBMAP_MODOP(items_max);
- words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
-
- /* Allocate runtime state of multiword bitmap */
- /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
- size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
- mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
- if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
- ASSERT(0);
- goto error1;
- }
- memset(mwbmap_p, 0, size);
-
- /* Initialize runtime multiword bitmap state */
- mwbmap_p->imaps = (uint16)words;
- mwbmap_p->ifree = (int32)items_max;
- mwbmap_p->total = (uint16)items_max;
-
- /* Setup magic, for use in audit of handle */
- mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
-
- /* Setup the second level bitmap of free indices */
- /* Mark all indices as available */
- for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
- mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
-#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
- mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
-#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
- }
-
- /* Ensure that extra indices are tagged as un-available */
- if (extra) { /* fixup the free ids in last bitmap and wd_count */
- uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
- *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
-#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
- mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
-#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
- }
-
- /* Setup the first level bitmap hierarchy */
- extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
- words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
-
- mwbmap_p->wmaps = (uint16)words;
-
- for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
- mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
- if (extra) {
- uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
- *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
- }
-
- return mwbmap_p;
-
-error1:
- return BCM_MWBMAP_INVALID_HDL;
-}
-
-/* Release resources used by multiword bitmap based small index allocator. */
-void
-bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
-{
- bcm_mwbmap_t * mwbmap_p;
-
- BCM_MWBMAP_AUDIT(mwbmap_hdl);
- mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
-
- MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
- + (sizeof(uint32) * mwbmap_p->imaps));
- return;
-}
-
-/* Allocate a unique small index using a multiword bitmap index allocator. */
-uint32 BCMFASTPATH
-bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
-{
- bcm_mwbmap_t * mwbmap_p;
- uint32 wordix, bitmap;
-
- BCM_MWBMAP_AUDIT(mwbmap_hdl);
- mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
-
- /* Start with the first hierarchy */
- for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
-
- bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
-
- if (bitmap != 0U) {
-
- uint32 count, bitix, *bitmap_p;
-
- bitmap_p = &mwbmap_p->wd_bitmap[wordix];
-
- /* clear all except trailing 1 */
- bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
- MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
- bcm_count_leading_zeros(bitmap));
- bitix = (BCM_MWBMAP_BITS_WORD - 1)
- - bcm_count_leading_zeros(bitmap); /* use asm clz */
- wordix = BCM_MWBMAP_MULOP(wordix) + bitix;
-
- /* Clear bit if wd count is 0, without conditional branch */
-#if defined(BCM_MWBMAP_USE_CNTSETBITS)
- count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
-#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
- mwbmap_p->wd_count[wordix]--;
- count = mwbmap_p->wd_count[wordix];
- MWBMAP_ASSERT(count ==
- (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
-#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
- MWBMAP_ASSERT(count >= 0);
-
- /* clear wd_bitmap bit if id_map count is 0 */
- bitmap = (count == 0) << bitix;
-
- MWBMAP_DBG((
- "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
- bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
-
- *bitmap_p ^= bitmap;
-
- /* Use bitix in the second hierarchy */
- bitmap_p = &mwbmap_p->id_bitmap[wordix];
-
- bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
- MWBMAP_ASSERT(bitmap != 0U);
-
- /* clear all except trailing 1 */
- bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
- MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
- bcm_count_leading_zeros(bitmap));
- bitix = BCM_MWBMAP_MULOP(wordix)
- + (BCM_MWBMAP_BITS_WORD - 1)
- - bcm_count_leading_zeros(bitmap); /* use asm clz */
-
- mwbmap_p->ifree--; /* decrement system wide free count */
- MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
-
- MWBMAP_DBG((
- "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
- bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
- mwbmap_p->ifree));
-
- *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
-
- return bitix;
- }
- }
-
- ASSERT(mwbmap_p->ifree == 0);
-
- return BCM_MWBMAP_INVALID_IDX;
-}
-
-/* Force an index at a specified position to be in use */
-void
-bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
-{
- bcm_mwbmap_t * mwbmap_p;
- uint32 count, wordix, bitmap, *bitmap_p;
-
- BCM_MWBMAP_AUDIT(mwbmap_hdl);
- mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
-
- ASSERT(bitix < mwbmap_p->total);
-
- /* Start with second hierarchy */
- wordix = BCM_MWBMAP_DIVOP(bitix);
- bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
- bitmap_p = &mwbmap_p->id_bitmap[wordix];
-
- ASSERT((*bitmap_p & bitmap) == bitmap);
-
- mwbmap_p->ifree--; /* update free count */
- ASSERT(mwbmap_p->ifree >= 0);
-
- MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
- bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
- mwbmap_p->ifree));
-
- *bitmap_p ^= bitmap; /* mark as in use */
-
- /* Update first hierarchy */
- bitix = wordix;
-
- wordix = BCM_MWBMAP_DIVOP(bitix);
- bitmap_p = &mwbmap_p->wd_bitmap[wordix];
-
-#if defined(BCM_MWBMAP_USE_CNTSETBITS)
- count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
-#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
- mwbmap_p->wd_count[bitix]--;
- count = mwbmap_p->wd_count[bitix];
- MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
-#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
- MWBMAP_ASSERT(count >= 0);
-
- bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix);
-
- MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
- BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
- (*bitmap_p) ^ bitmap, count));
-
- *bitmap_p ^= bitmap; /* mark as in use */
-
- return;
-}
-
-/* Free a previously allocated index back into the multiword bitmap allocator */
-void BCMFASTPATH
-bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
-{
- bcm_mwbmap_t * mwbmap_p;
- uint32 wordix, bitmap, *bitmap_p;
-
- BCM_MWBMAP_AUDIT(mwbmap_hdl);
- mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
-
- ASSERT(bitix < mwbmap_p->total);
-
- /* Start with second level hierarchy */
- wordix = BCM_MWBMAP_DIVOP(bitix);
- bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
- bitmap_p = &mwbmap_p->id_bitmap[wordix];
-
- ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */
-
- mwbmap_p->ifree++; /* update free count */
- ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
-
- MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
- bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
- mwbmap_p->ifree));
-
- *bitmap_p |= bitmap; /* mark as available */
-
- /* Now update first level hierarchy */
-
- bitix = wordix;
-
- wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
- bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
- bitmap_p = &mwbmap_p->wd_bitmap[wordix];
-
-#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
- mwbmap_p->wd_count[bitix]++;
-#endif
-
-#if defined(BCM_MWBMAP_DEBUG)
- {
- uint32 count;
-#if defined(BCM_MWBMAP_USE_CNTSETBITS)
- count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
-#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
- count = mwbmap_p->wd_count[bitix];
- MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
-#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
-
- MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
-
- MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
- bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
- }
-#endif /* BCM_MWBMAP_DEBUG */
-
- *bitmap_p |= bitmap;
-
- return;
-}
-
-/* Fetch the toal number of free indices in the multiword bitmap allocator */
-uint32
-bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
-{
- bcm_mwbmap_t * mwbmap_p;
-
- BCM_MWBMAP_AUDIT(mwbmap_hdl);
- mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
-
- ASSERT(mwbmap_p->ifree >= 0);
-
- return mwbmap_p->ifree;
-}
-
-/* Determine whether an index is inuse or free */
-bool
-bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
-{
- bcm_mwbmap_t * mwbmap_p;
- uint32 wordix, bitmap;
-
- BCM_MWBMAP_AUDIT(mwbmap_hdl);
- mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
-
- ASSERT(bitix < mwbmap_p->total);
-
- wordix = BCM_MWBMAP_DIVOP(bitix);
- bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
-
- return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
-}
-
-/* Debug dump a multiword bitmap allocator */
-void
-bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
-{
- uint32 ix, count;
- bcm_mwbmap_t * mwbmap_p;
-
- BCM_MWBMAP_AUDIT(mwbmap_hdl);
- mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
-
- printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p,
- mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
- for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
- printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
- bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
- printf("\n");
- }
- for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
-#if defined(BCM_MWBMAP_USE_CNTSETBITS)
- count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
-#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
- count = mwbmap_p->wd_count[ix];
- MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
-#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
- printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
- bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
- printf("\n");
- }
-
- return;
-}
-
-/* Audit a hierarchical multiword bitmap */
-void
-bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
-{
- bcm_mwbmap_t * mwbmap_p;
- uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
-
- mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
-
- for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
-
- bitmap_p = &mwbmap_p->wd_bitmap[wordix];
-
- for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
- if ((*bitmap_p) & (1 << bitix)) {
- idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
-#if defined(BCM_MWBMAP_USE_CNTSETBITS)
- count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
-#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
- count = mwbmap_p->wd_count[idmap_ix];
- ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
-#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
- ASSERT(count != 0U);
- free_cnt += count;
- }
- }
- }
-
- ASSERT((int)free_cnt == mwbmap_p->ifree);
-}
-/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
-
-/* Simple 16bit Id allocator using a stack implementation. */
-typedef struct id16_map {
- uint32 failures; /* count of failures */
- void *dbg; /* debug placeholder */
- uint16 total; /* total number of ids managed by allocator */
- uint16 start; /* start value of 16bit ids to be managed */
- int stack_idx; /* index into stack of available ids */
- uint16 stack[0]; /* stack of 16 bit ids */
-} id16_map_t;
-
-#define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \
- (sizeof(uint16) * (items)))
-
-#if defined(BCM_DBG)
-
-/* Uncomment BCM_DBG_ID16 to debug double free */
-/* #define BCM_DBG_ID16 */
-
-typedef struct id16_map_dbg {
- uint16 total;
- bool avail[0];
-} id16_map_dbg_t;
-#define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \
- (sizeof(bool) * (items)))
-#define ID16_MAP_MSG(x) print x
-#else
-#define ID16_MAP_MSG(x)
-#endif /* BCM_DBG */
-
-void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
-id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
-{
- uint16 idx, val16;
- id16_map_t * id16_map;
-
- ASSERT(total_ids > 0);
-
- /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
- * with random values.
- */
- ASSERT((start_val16 == ID16_UNDEFINED) ||
- (start_val16 + total_ids) < ID16_INVALID);
-
- id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
- if (id16_map == NULL) {
- return NULL;
- }
-
- id16_map->total = total_ids;
- id16_map->start = start_val16;
- id16_map->failures = 0;
- id16_map->dbg = NULL;
-
- /*
- * Populate stack with 16bit id values, commencing with start_val16.
- * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
- */
- id16_map->stack_idx = -1;
-
- if (id16_map->start != ID16_UNDEFINED) {
- val16 = start_val16;
-
- for (idx = 0; idx < total_ids; idx++, val16++) {
- id16_map->stack_idx = idx;
- id16_map->stack[id16_map->stack_idx] = val16;
- }
- }
-
-#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
- if (id16_map->start != ID16_UNDEFINED) {
- id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
-
- if (id16_map->dbg) {
- id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
-
- id16_map_dbg->total = total_ids;
- for (idx = 0; idx < total_ids; idx++) {
- id16_map_dbg->avail[idx] = TRUE;
- }
- }
- }
-#endif /* BCM_DBG && BCM_DBG_ID16 */
-
- return (void *)id16_map;
-}
-
-void * /* Destruct an id16 allocator instance */
-id16_map_fini(osl_t *osh, void * id16_map_hndl)
-{
- uint16 total_ids;
- id16_map_t * id16_map;
-
- if (id16_map_hndl == NULL)
- return NULL;
-
- id16_map = (id16_map_t *)id16_map_hndl;
-
- total_ids = id16_map->total;
- ASSERT(total_ids > 0);
-
-#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
- if (id16_map->dbg) {
- MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
- id16_map->dbg = NULL;
- }
-#endif /* BCM_DBG && BCM_DBG_ID16 */
-
- id16_map->total = 0;
- MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
-
- return NULL;
-}
-
-void
-id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
-{
- uint16 idx, val16;
- id16_map_t * id16_map;
-
- ASSERT(total_ids > 0);
- /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
- * with random values.
- */
- ASSERT((start_val16 == ID16_UNDEFINED) ||
- (start_val16 + total_ids) < ID16_INVALID);
-
- id16_map = (id16_map_t *)id16_map_hndl;
- if (id16_map == NULL) {
- return;
- }
-
- id16_map->total = total_ids;
- id16_map->start = start_val16;
- id16_map->failures = 0;
-
- /* Populate stack with 16bit id values, commencing with start_val16 */
- id16_map->stack_idx = -1;
-
- if (id16_map->start != ID16_UNDEFINED) {
- val16 = start_val16;
-
- for (idx = 0; idx < total_ids; idx++, val16++) {
- id16_map->stack_idx = idx;
- id16_map->stack[id16_map->stack_idx] = val16;
- }
- }
-
-#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
- if (id16_map->start != ID16_UNDEFINED) {
- if (id16_map->dbg) {
- id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
-
- id16_map_dbg->total = total_ids;
- for (idx = 0; idx < total_ids; idx++) {
- id16_map_dbg->avail[idx] = TRUE;
- }
- }
- }
-#endif /* BCM_DBG && BCM_DBG_ID16 */
-}
-
-uint16 BCMFASTPATH /* Allocate a unique 16bit id */
-id16_map_alloc(void * id16_map_hndl)
-{
- uint16 val16;
- id16_map_t * id16_map;
-
- ASSERT(id16_map_hndl != NULL);
-
- id16_map = (id16_map_t *)id16_map_hndl;
-
- ASSERT(id16_map->total > 0);
-
- if (id16_map->stack_idx < 0) {
- id16_map->failures++;
- return ID16_INVALID;
- }
-
- val16 = id16_map->stack[id16_map->stack_idx];
- id16_map->stack_idx--;
-
-#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
- ASSERT((id16_map->start == ID16_UNDEFINED) ||
- (val16 < (id16_map->start + id16_map->total)));
-
- if (id16_map->dbg) { /* Validate val16 */
- id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
-
- ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
- id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
- }
-#endif /* BCM_DBG && BCM_DBG_ID16 */
-
- return val16;
-}
-
-
-void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
-id16_map_free(void * id16_map_hndl, uint16 val16)
-{
- id16_map_t * id16_map;
-
- ASSERT(id16_map_hndl != NULL);
-
- id16_map = (id16_map_t *)id16_map_hndl;
-
-#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
- ASSERT((id16_map->start == ID16_UNDEFINED) ||
- (val16 < (id16_map->start + id16_map->total)));
-
- if (id16_map->dbg) { /* Validate val16 */
- id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
-
- ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
- id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
- }
-#endif /* BCM_DBG && BCM_DBG_ID16 */
-
- id16_map->stack_idx++;
- id16_map->stack[id16_map->stack_idx] = val16;
-}
-
-uint32 /* Returns number of failures to allocate an unique id16 */
-id16_map_failures(void * id16_map_hndl)
-{
- ASSERT(id16_map_hndl != NULL);
- return ((id16_map_t *)id16_map_hndl)->failures;
-}
-
-bool
-id16_map_audit(void * id16_map_hndl)
-{
- int idx;
- int insane = 0;
- id16_map_t * id16_map;
-
- ASSERT(id16_map_hndl != NULL);
-
- id16_map = (id16_map_t *)id16_map_hndl;
-
- ASSERT(id16_map->stack_idx >= -1);
- ASSERT(id16_map->stack_idx < (int)id16_map->total);
-
- if (id16_map->start == ID16_UNDEFINED)
- goto done;
-
- for (idx = 0; idx <= id16_map->stack_idx; idx++) {
- ASSERT(id16_map->stack[idx] >= id16_map->start);
- ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
-
-#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
- if (id16_map->dbg) {
- uint16 val16 = id16_map->stack[idx];
- if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
- insane |= 1;
- ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
- id16_map_hndl, idx, val16));
- }
- }
-#endif /* BCM_DBG && BCM_DBG_ID16 */
- }
-
-#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
- if (id16_map->dbg) {
- uint16 avail = 0; /* Audit available ids counts */
- for (idx = 0; idx < id16_map_dbg->total; idx++) {
- if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
- avail++;
- }
- if (avail && (avail != (id16_map->stack_idx + 1))) {
- insane |= 1;
- ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
- id16_map_hndl, avail, id16_map->stack_idx));
- }
- }
-#endif /* BCM_DBG && BCM_DBG_ID16 */
-
-done:
- /* invoke any other system audits */
- return (!!insane);
-}
-/* END: Simple id16 allocator */
-
-
-#endif
-
-/* calculate a >> b; and returns only lower 32 bits */
-void
-bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
-{
- uint32 a1 = a_high, a0 = a_low, r0 = 0;
-
- if (b == 0) {
- r0 = a_low;
- *r = r0;
- return;
- }
-
- if (b < 32) {
- a0 = a0 >> b;
- a1 = a1 & ((1 << b) - 1);
- a1 = a1 << (32 - b);
- r0 = a0 | a1;
- *r = r0;
- return;
- } else {
- r0 = a1 >> (b - 32);
- *r = r0;
- return;
- }
-
-}
-
-/* calculate a + b where a is a 64 bit number and b is a 32 bit number */
-void
-bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset)
-{
- uint32 r1_lo = *r_lo;
- (*r_lo) += offset;
- if (*r_lo < r1_lo)
- (*r_hi) ++;
-}
-
-/* calculate a - b where a is a 64 bit number and b is a 32 bit number */
-void
-bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset)
-{
- uint32 r1_lo = *r_lo;
- (*r_lo) -= offset;
- if (*r_lo > r1_lo)
- (*r_hi) --;
+ return ((e <= 0) && (e >= BCME_LAST));
}
#ifdef DEBUG_COUNTER
@@ -3534,85 +3793,6 @@
#define counter_printlog(a) do {} while (0)
#endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
#endif /* DEBUG_COUNTER */
-
-#if defined(BCMDRIVER) && !defined(_CFEZ_)
-void
-dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
-{
- uint32 mem_size;
- mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
- if (pool)
- MFREE(osh, pool, mem_size);
-}
-dll_pool_t *
-dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size)
-{
- uint32 mem_size, i;
- dll_pool_t * dll_pool_p;
- dll_t * elem_p;
-
- ASSERT(elem_size > sizeof(dll_t));
-
- mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
-
- if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) {
- printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
- elems_max, elem_size);
- ASSERT(0);
- return dll_pool_p;
- }
-
- dll_init(&dll_pool_p->free_list);
- dll_pool_p->elems_max = elems_max;
- dll_pool_p->elem_size = elem_size;
-
- elem_p = dll_pool_p->elements;
- for (i = 0; i < elems_max; i++) {
- dll_append(&dll_pool_p->free_list, elem_p);
- elem_p = (dll_t *)((uintptr)elem_p + elem_size);
- }
-
- dll_pool_p->free_count = elems_max;
-
- return dll_pool_p;
-}
-
-
-void *
-dll_pool_alloc(dll_pool_t * dll_pool_p)
-{
- dll_t * elem_p;
-
- if (dll_pool_p->free_count == 0) {
- ASSERT(dll_empty(&dll_pool_p->free_list));
- return NULL;
- }
-
- elem_p = dll_head_p(&dll_pool_p->free_list);
- dll_delete(elem_p);
- dll_pool_p->free_count -= 1;
-
- return (void *)elem_p;
-}
-
-void
-dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p)
-{
- dll_t * node_p = (dll_t *)elem_p;
- dll_prepend(&dll_pool_p->free_list, node_p);
- dll_pool_p->free_count += 1;
-}
-
-
-void
-dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
-{
- dll_t * node_p = (dll_t *)elem_p;
- dll_append(&dll_pool_p->free_list, node_p);
- dll_pool_p->free_count += 1;
-}
-
-#endif
/* calculate partial checksum */
static uint32
@@ -3674,5 +3854,498 @@
ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2;
/* return calculated chksum */
- return ip_cksum(sum, ptr, ip_len - OFFSETOF(struct ipv4_hdr, src_ip));
+ return ip_cksum(sum, ptr, (uint32)((uint)ip_len - OFFSETOF(struct ipv4_hdr, src_ip)));
+}
+
+/* calculate TCP header checksum using partial sum */
+static uint16
+tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len)
+{
+ uint8 *ptr = tcp_hdr;
+
+ ASSERT(tcp_hdr != NULL);
+ ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
+
+ /* partial TCP cksum skipping the chksum field */
+ sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum));
+ ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2;
+
+ /* return calculated chksum */
+ return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr));
+}
+
+struct tcp_pseudo_hdr {
+ uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */
+ uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */
+ uint8 zero;
+ uint8 prot;
+ uint16 tcp_size;
+};
+
+/* calculate IPv4 TCP header checksum
+ * - input ip and tcp points to IP and TCP header in network order
+ * - output cksum is in network order
+ */
+uint16
+ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len)
+{
+ struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip;
+ struct tcp_pseudo_hdr tcp_ps;
+ uint32 sum = 0;
+
+ ASSERT(ip != NULL);
+ ASSERT(tcp != NULL);
+ ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
+
+ if (!ip || !tcp || !(tcp_len >= TCP_MIN_HEADER_LEN))
+ return 0;
+ /* pseudo header cksum */
+ memset(&tcp_ps, 0, sizeof(tcp_ps));
+ memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN);
+ memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN);
+ tcp_ps.zero = 0;
+ tcp_ps.prot = ip_hdr->prot;
+ tcp_ps.tcp_size = hton16(tcp_len);
+ sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps));
+
+ /* return calculated TCP header chksum */
+ return tcp_hdr_chksum(sum, tcp, tcp_len);
+}
+
+struct ipv6_pseudo_hdr {
+ uint8 saddr[IPV6_ADDR_LEN];
+ uint8 daddr[IPV6_ADDR_LEN];
+ uint16 payload_len;
+ uint8 zero;
+ uint8 next_hdr;
+};
+
+/* calculate IPv6 TCP header checksum
+ * - input ipv6 and tcp points to IPv6 and TCP header in network order
+ * - output cksum is in network order
+ */
+uint16
+ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len)
+{
+ struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6;
+ struct ipv6_pseudo_hdr ipv6_pseudo;
+ uint32 sum = 0;
+
+ ASSERT(ipv6 != NULL);
+ ASSERT(tcp != NULL);
+ ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
+
+ if (!ipv6 || !tcp || !(tcp_len >= TCP_MIN_HEADER_LEN))
+ return 0;
+ /* pseudo header cksum */
+ memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo));
+ memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr,
+ sizeof(ipv6_pseudo.saddr));
+ memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr,
+ sizeof(ipv6_pseudo.daddr));
+ ipv6_pseudo.payload_len = ipv6_hdr->payload_len;
+ ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr;
+ sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo));
+
+ /* return calculated TCP header chksum */
+ return tcp_hdr_chksum(sum, tcp, tcp_len);
+}
+
+void *_bcmutils_dummy_fn = NULL;
+
+/* GROUP 1 --- start
+ * These function under GROUP 1 are general purpose functions to do complex number
+ * calculations and square root calculation.
+ */
+
+uint32 sqrt_int(uint32 value)
+{
+ uint32 root = 0, shift = 0;
+
+ /* Compute integer nearest to square root of input integer value */
+ for (shift = 0; shift < 32; shift += 2) {
+ if (((0x40000000 >> shift) + root) <= value) {
+ value -= ((0x40000000 >> shift) + root);
+ root = (root >> 1) | (0x40000000 >> shift);
+ }
+ else {
+ root = root >> 1;
+ }
+ }
+
+ /* round to the nearest integer */
+ if (root < value) ++root;
+
+ return root;
+}
+/* GROUP 1 --- end */
+
+/* read/write field in a consecutive bits in an octet array.
+ * 'addr' is the octet array's start byte address
+ * 'size' is the octet array's byte size
+ * 'stbit' is the value's start bit offset
+ * 'nbits' is the value's bit size
+ * This set of utilities are for convenience. Don't use them
+ * in time critical/data path as there's a great overhead in them.
+ */
+void
+setbits(uint8 *addr, uint size, uint stbit, uint nbits, uint32 val)
+{
+ uint fbyte = stbit >> 3; /* first byte */
+ uint lbyte = (stbit + nbits - 1) >> 3; /* last byte */
+ uint fbit = stbit & 7; /* first bit in the first byte */
+ uint rbits = (nbits > 8 - fbit ?
+ nbits - (8 - fbit) :
+ 0) & 7; /* remaining bits of the last byte when not 0 */
+ uint8 mask;
+ uint byte;
+
+ BCM_REFERENCE(size);
+
+ ASSERT(fbyte < size);
+ ASSERT(lbyte < size);
+ ASSERT(nbits <= (sizeof(val) << 3));
+
+ /* all bits are in the same byte */
+ if (fbyte == lbyte) {
+ mask = (uint8)(((1 << nbits) - 1) << fbit);
+ addr[fbyte] &= ~mask;
+ addr[fbyte] |= (uint8)(val << fbit);
+ return;
+ }
+
+ /* first partial byte */
+ if (fbit > 0) {
+ mask = (uint8)(0xff << fbit);
+ addr[fbyte] &= ~mask;
+ addr[fbyte] |= (uint8)(val << fbit);
+ val >>= (8 - fbit);
+ nbits -= (8 - fbit);
+ fbyte ++; /* first full byte */
+ }
+
+ /* last partial byte */
+ if (rbits > 0) {
+ mask = (uint8)((1 << rbits) - 1);
+ addr[lbyte] &= ~mask;
+ addr[lbyte] |= (uint8)(val >> (nbits - rbits));
+ lbyte --; /* last full byte */
+ }
+
+ /* remaining full byte(s) */
+ for (byte = fbyte; byte <= lbyte; byte ++) {
+ addr[byte] = (uint8)val;
+ val >>= 8;
+ }
+}
+
+uint32
+getbits(const uint8 *addr, uint size, uint stbit, uint nbits)
+{
+ uint fbyte = stbit >> 3; /* first byte */
+ uint lbyte = (stbit + nbits - 1) >> 3; /* last byte */
+ uint fbit = stbit & 7; /* first bit in the first byte */
+ uint rbits = (nbits > 8 - fbit ?
+ nbits - (8 - fbit) :
+ 0) & 7; /* remaining bits of the last byte when not 0 */
+ uint32 val = 0;
+ uint bits = 0; /* bits in first partial byte */
+ uint8 mask;
+ uint byte;
+
+ BCM_REFERENCE(size);
+
+ ASSERT(fbyte < size);
+ ASSERT(lbyte < size);
+ ASSERT(nbits <= (sizeof(val) << 3));
+
+ /* all bits are in the same byte */
+ if (fbyte == lbyte) {
+ mask = (uint8)(((1 << nbits) - 1) << fbit);
+ val = (addr[fbyte] & mask) >> fbit;
+ return val;
+ }
+
+ /* first partial byte */
+ if (fbit > 0) {
+ bits = 8 - fbit;
+ mask = (uint8)(0xFFu << fbit);
+ val |= (addr[fbyte] & mask) >> fbit;
+ fbyte ++; /* first full byte */
+ }
+
+ /* last partial byte */
+ if (rbits > 0) {
+ mask = (uint8)((1 << rbits) - 1);
+ val |= (uint32)((addr[lbyte] & mask) << (nbits - rbits));
+ lbyte --; /* last full byte */
+ }
+
+ /* remaining full byte(s) */
+ for (byte = fbyte; byte <= lbyte; byte ++) {
+ val |= (uint32)((addr[byte] << (((byte - fbyte) << 3) + bits)));
+ }
+
+ return val;
+}
+
+#ifdef BCMDRIVER
+
+/** allocate variable sized data with 'size' bytes. note: vld should NOT be null.
+ */
+int
+bcm_vdata_alloc(osl_t *osh, var_len_data_t *vld, uint32 size)
+{
+ int ret = BCME_ERROR;
+ uint8 *dat = NULL;
+
+ if (vld == NULL) {
+ ASSERT(0);
+ goto done;
+ }
+
+ /* trying to allocate twice? */
+ if (vld->vdata != NULL) {
+ ASSERT(0);
+ goto done;
+ }
+
+ /* trying to allocate 0 size? */
+ if (size == 0) {
+ ASSERT(0);
+ ret = BCME_BADARG;
+ goto done;
+ }
+
+ dat = MALLOCZ(osh, size);
+ if (dat == NULL) {
+ ret = BCME_NOMEM;
+ goto done;
+ }
+ vld->vlen = size;
+ vld->vdata = dat;
+ ret = BCME_OK;
+done:
+ return ret;
+}
+
+/** free memory associated with variable sized data. note: vld should NOT be null.
+ */
+int
+bcm_vdata_free(osl_t *osh, var_len_data_t *vld)
+{
+ int ret = BCME_ERROR;
+
+ if (vld == NULL) {
+ ASSERT(0);
+ goto done;
+ }
+
+ if (vld->vdata) {
+ MFREE(osh, vld->vdata, vld->vlen);
+ vld->vdata = NULL;
+ vld->vlen = 0;
+ ret = BCME_OK;
+ }
+done:
+ return ret;
+}
+
+#endif /* BCMDRIVER */
+
+/* Count the number of elements not matching a given value in a null terminated array */
+int
+array_value_mismatch_count(uint8 value, uint8 *array, int array_size)
+{
+ int i;
+ int count = 0;
+
+ for (i = 0; i < array_size; i++) {
+ /* exit if a null terminator is found */
+ if (array[i] == 0) {
+ break;
+ }
+ if (array[i] != value) {
+ count++;
+ }
+ }
+ return count;
+}
+
+/* Count the number of non-zero elements in an uint8 array */
+int
+array_nonzero_count(uint8 *array, int array_size)
+{
+ return array_value_mismatch_count(0, array, array_size);
+}
+
+/* Count the number of non-zero elements in an int16 array */
+int
+array_nonzero_count_int16(int16 *array, int array_size)
+{
+ int i;
+ int count = 0;
+
+ for (i = 0; i < array_size; i++) {
+ if (array[i] != 0) {
+ count++;
+ }
+ }
+ return count;
+}
+
+/* Count the number of zero elements in an uint8 array */
+int
+array_zero_count(uint8 *array, int array_size)
+{
+ int i;
+ int count = 0;
+
+ for (i = 0; i < array_size; i++) {
+ if (array[i] == 0) {
+ count++;
+ }
+ }
+ return count;
+}
+
+/* Validate an array that can be 1 of 2 data types.
+ * One of array1 or array2 should be non-NULL. The other should be NULL.
+ */
+static int
+verify_ordered_array(uint8 *array1, int16 *array2, int array_size,
+ int range_lo, int range_hi, bool err_if_no_zero_term, bool is_ordered)
+{
+ int ret;
+ int i;
+ int val = 0;
+ int prev_val = 0;
+
+ ret = err_if_no_zero_term ? BCME_NOTFOUND : BCME_OK;
+
+ /* Check that:
+ * - values are in strict descending order.
+ * - values are within the valid range.
+ */
+ for (i = 0; i < array_size; i++) {
+ if (array1) {
+ val = (int)array1[i];
+ } else if (array2) {
+ val = (int)array2[i];
+ } else {
+ /* both array parameters are NULL */
+ return BCME_NOTFOUND;
+ }
+ if (val == 0) {
+ /* array is zero-terminated */
+ ret = BCME_OK;
+ break;
+ }
+
+ if (is_ordered && i > 0 && val >= prev_val) {
+ /* array is not in descending order */
+ ret = BCME_BADOPTION;
+ break;
+ }
+ prev_val = val;
+
+ if (val < range_lo || val > range_hi) {
+ /* array value out of range */
+ ret = BCME_RANGE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* Validate an ordered uint8 configuration array */
+int
+verify_ordered_array_uint8(uint8 *array, int array_size,
+ uint8 range_lo, uint8 range_hi)
+{
+ return verify_ordered_array(array, NULL, array_size, (int)range_lo, (int)range_hi,
+ TRUE, TRUE);
+}
+
+/* Validate an ordered int16 non-zero-terminated configuration array */
+int
+verify_ordered_array_int16(int16 *array, int array_size,
+ int16 range_lo, int16 range_hi)
+{
+ return verify_ordered_array(NULL, array, array_size, (int)range_lo, (int)range_hi,
+ FALSE, TRUE);
+}
+
+/* Validate all values in an array are in range */
+int
+verify_array_values(uint8 *array, int array_size,
+ int range_lo, int range_hi, bool zero_terminated)
+{
+ int ret = BCME_OK;
+ int i;
+ int val = 0;
+
+ /* Check that:
+ * - values are in strict descending order.
+ * - values are within the valid range.
+ */
+ for (i = 0; i < array_size; i++) {
+ val = (int)array[i];
+ if (val == 0 && zero_terminated) {
+ ret = BCME_OK;
+ break;
+ }
+ if (val < range_lo || val > range_hi) {
+ /* array value out of range */
+ ret = BCME_RANGE;
+ break;
+ }
+ }
+ return ret;
+}
+
+/* Adds/replaces NVRAM variable with given value
+ * varbuf[in,out] - Buffer with NVRAM variables (sequence of zero-terminated 'name=value' records,
+ * terminated with additional zero)
+ * buflen[in] - Length of buffer (may, even should, have some unused space)
+ * variable[in] - Variable to add/replace in 'name=value' form
+ * datalen[out,opt] - Optional output parameter - resulting length of data in buffer
+ * Returns TRUE on success, FALSE if buffer too short or variable specified incorrectly
+ */
+bool
+replace_nvram_variable(char *varbuf, unsigned int buflen, const char *variable,
+ unsigned int *datalen)
+{
+ char *p;
+ int variable_heading_len, record_len, variable_record_len = (int)strlen(variable) + 1;
+ char *buf_end = varbuf + buflen;
+ p = strchr(variable, '=');
+ if (!p) {
+ return FALSE;
+ }
+ /* Length of given variable name, followed by '=' */
+ variable_heading_len = (int)((const char *)(p + 1) - variable);
+ /* Scanning NVRAM, record by record up to trailing 0 */
+ for (p = varbuf; *p; p += strlen(p) + 1) {
+ /* If given variable found - remove it */
+ if (!strncmp(p, variable, (size_t)variable_heading_len)) {
+ record_len = (int)strlen(p) + 1;
+ memmove_s(p, buf_end - p, p + record_len,
+ (size_t)(buf_end - (p + record_len)));
+ }
+ }
+ /* If buffer does not have space for given variable - return FALSE */
+ if ((p + variable_record_len + 1) > buf_end) {
+ return FALSE;
+ }
+ /* Copy given variable to end of buffer */
+ memmove_s(p, buf_end - p, variable, (size_t)variable_record_len);
+ /* Adding trailing 0 */
+ p[variable_record_len] = 0;
+ /* Setting optional output parameter - length of data in buffer */
+ if (datalen) {
+ *datalen = (unsigned int)(p + variable_record_len + 1 - varbuf);
+ }
+ return TRUE;
}
--
Gitblit v1.6.2