xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd_indep_power/bcmutils.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Driver O/S-independent utility routines
4  *
5  * Copyright (C) 1999-2017, Broadcom Corporation
6  *
7  *      Unless you and Broadcom execute a separate written software license
8  * agreement governing use of this software, this software is licensed to you
9  * under the terms of the GNU General Public License version 2 (the "GPL"),
10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11  * following added to such license:
12  *
13  *      As a special exception, the copyright holders of this software give you
14  * permission to link this software with independent modules, and to copy and
15  * distribute the resulting executable under terms of your choice, provided that
16  * you also meet, for each linked independent module, the terms and conditions of
17  * the license of that module.  An independent module is a module which is not
18  * derived from this software.  The special exception does not apply to any
19  * modifications of the software.
20  *
21  *      Notwithstanding the above, under no circumstances may you combine this
22  * software in any way with any other Broadcom software provided under a license
23  * other than the GPL, without Broadcom's express prior written consent.
24  *
25  *
26  * <<Broadcom-WL-IPTag/Open:>>
27  *
28  * $Id: bcmutils.c 699163 2017-05-12 05:18:23Z $
29  */
30 
31 #include <bcm_cfg.h>
32 #include <typedefs.h>
33 #include <bcmdefs.h>
34 #include <stdarg.h>
35 #ifdef BCMDRIVER
36 
37 #include <osl.h>
38 #include <bcmutils.h>
39 
40 #else /* !BCMDRIVER */
41 
42 #include <stdio.h>
43 #include <string.h>
44 #include <bcmutils.h>
45 
46 #if defined(BCMEXTSUP)
47 #include <bcm_osl.h>
48 #endif
49 
50 #ifndef ASSERT
51 #define ASSERT(exp)
52 #endif
53 
54 #endif /* !BCMDRIVER */
55 
56 #include <bcmendian.h>
57 #include <bcmdevs.h>
58 #include <ethernet.h>
59 #include <vlan.h>
60 #include <bcmip.h>
61 #include <802.1d.h>
62 #include <802.11.h>
63 #include <bcmip.h>
64 #include <bcmipv6.h>
65 #include <bcmtcp.h>
66 
67 /* Look-up table to calculate head room present in a number */
68 static const uint8 msb_table[] = {
69 	0, 1, 2, 2, 3, 3, 3, 3,
70 	4, 4, 4, 4, 4, 4, 4, 4,
71 	5, 5, 5, 5, 5, 5, 5, 5,
72 	5, 5, 5, 5, 5, 5, 5, 5,
73 	6, 6, 6, 6, 6, 6, 6, 6,
74 	6, 6, 6, 6, 6, 6, 6, 6,
75 	6, 6, 6, 6, 6, 6, 6, 6,
76 	6, 6, 6, 6, 6, 6, 6, 6,
77 	7, 7, 7, 7, 7, 7, 7, 7,
78 	7, 7, 7, 7, 7, 7, 7, 7,
79 	7, 7, 7, 7, 7, 7, 7, 7,
80 	7, 7, 7, 7, 7, 7, 7, 7,
81 	7, 7, 7, 7, 7, 7, 7, 7,
82 	7, 7, 7, 7, 7, 7, 7, 7,
83 	7, 7, 7, 7, 7, 7, 7, 7,
84 	7, 7, 7, 7, 7, 7, 7, 7,
85 	8, 8, 8, 8, 8, 8, 8, 8,
86 	8, 8, 8, 8, 8, 8, 8, 8,
87 	8, 8, 8, 8, 8, 8, 8, 8,
88 	8, 8, 8, 8, 8, 8, 8, 8,
89 	8, 8, 8, 8, 8, 8, 8, 8,
90 	8, 8, 8, 8, 8, 8, 8, 8,
91 	8, 8, 8, 8, 8, 8, 8, 8,
92 	8, 8, 8, 8, 8, 8, 8, 8,
93 	8, 8, 8, 8, 8, 8, 8, 8,
94 	8, 8, 8, 8, 8, 8, 8, 8,
95 	8, 8, 8, 8, 8, 8, 8, 8,
96 	8, 8, 8, 8, 8, 8, 8, 8,
97 	8, 8, 8, 8, 8, 8, 8, 8,
98 	8, 8, 8, 8, 8, 8, 8, 8,
99 	8, 8, 8, 8, 8, 8, 8, 8,
100 	8, 8, 8, 8, 8, 8, 8, 8,
101 };
102 
103 void *_bcmutils_dummy_fn = NULL;
104 
105 
106 
107 
108 #ifdef BCMDRIVER
109 
110 
111 /* copy a pkt buffer chain into a buffer */
112 uint
pktcopy(osl_t * osh,void * p,uint offset,int len,uchar * buf)113 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
114 {
115 	uint n, ret = 0;
116 
117 	if (len < 0)
118 		len = 4096;	/* "infinite" */
119 
120 	/* skip 'offset' bytes */
121 	for (; p && offset; p = PKTNEXT(osh, p)) {
122 		if (offset < (uint)PKTLEN(osh, p))
123 			break;
124 		offset -= PKTLEN(osh, p);
125 	}
126 
127 	if (!p)
128 		return 0;
129 
130 	/* copy the data */
131 	for (; p && len; p = PKTNEXT(osh, p)) {
132 		n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
133 		bcopy(PKTDATA(osh, p) + offset, buf, n);
134 		buf += n;
135 		len -= n;
136 		ret += n;
137 		offset = 0;
138 	}
139 
140 	return ret;
141 }
142 
143 /* copy a buffer into a pkt buffer chain */
144 uint
pktfrombuf(osl_t * osh,void * p,uint offset,int len,uchar * buf)145 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
146 {
147 	uint n, ret = 0;
148 
149 
150 	/* skip 'offset' bytes */
151 	for (; p && offset; p = PKTNEXT(osh, p)) {
152 		if (offset < (uint)PKTLEN(osh, p))
153 			break;
154 		offset -= PKTLEN(osh, p);
155 	}
156 
157 	if (!p)
158 		return 0;
159 
160 	/* copy the data */
161 	for (; p && len; p = PKTNEXT(osh, p)) {
162 		n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
163 		bcopy(buf, PKTDATA(osh, p) + offset, n);
164 		buf += n;
165 		len -= n;
166 		ret += n;
167 		offset = 0;
168 	}
169 
170 	return ret;
171 }
172 
173 
174 
175 /* return total length of buffer chain */
176 uint BCMFASTPATH
pkttotlen(osl_t * osh,void * p)177 pkttotlen(osl_t *osh, void *p)
178 {
179 	uint total;
180 	int len;
181 
182 	total = 0;
183 	for (; p; p = PKTNEXT(osh, p)) {
184 		len = PKTLEN(osh, p);
185 		total += len;
186 #ifdef BCMLFRAG
187 		if (BCMLFRAG_ENAB()) {
188 			if (PKTISFRAG(osh, p)) {
189 				total += PKTFRAGTOTLEN(osh, p);
190 			}
191 		}
192 #endif
193 	}
194 
195 	return (total);
196 }
197 
198 /* return the last buffer of chained pkt */
199 void *
pktlast(osl_t * osh,void * p)200 pktlast(osl_t *osh, void *p)
201 {
202 	for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
203 		;
204 
205 	return (p);
206 }
207 
208 /* count segments of a chained packet */
209 uint BCMFASTPATH
pktsegcnt(osl_t * osh,void * p)210 pktsegcnt(osl_t *osh, void *p)
211 {
212 	uint cnt;
213 
214 	for (cnt = 0; p; p = PKTNEXT(osh, p)) {
215 		cnt++;
216 #ifdef BCMLFRAG
217 		if (BCMLFRAG_ENAB()) {
218 			if (PKTISFRAG(osh, p)) {
219 				cnt += PKTFRAGTOTNUM(osh, p);
220 			}
221 		}
222 #endif
223 	}
224 
225 	return cnt;
226 }
227 
228 
229 /* count segments of a chained packet */
230 uint BCMFASTPATH
pktsegcnt_war(osl_t * osh,void * p)231 pktsegcnt_war(osl_t *osh, void *p)
232 {
233 	uint cnt;
234 	uint8 *pktdata;
235 	uint len, remain, align64;
236 
237 	for (cnt = 0; p; p = PKTNEXT(osh, p)) {
238 		cnt++;
239 		len = PKTLEN(osh, p);
240 		if (len > 128) {
241 			pktdata = (uint8 *)PKTDATA(osh, p);	/* starting address of data */
242 			/* Check for page boundary straddle (2048B) */
243 			if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
244 				cnt++;
245 
246 			align64 = (uint)((uintptr)pktdata & 0x3f);	/* aligned to 64B */
247 			align64 = (64 - align64) & 0x3f;
248 			len -= align64;		/* bytes from aligned 64B to end */
249 			/* if aligned to 128B, check for MOD 128 between 1 to 4B */
250 			remain = len % 128;
251 			if (remain > 0 && remain <= 4)
252 				cnt++;		/* add extra seg */
253 		}
254 	}
255 
256 	return cnt;
257 }
258 
259 uint8 * BCMFASTPATH
pktdataoffset(osl_t * osh,void * p,uint offset)260 pktdataoffset(osl_t *osh, void *p,  uint offset)
261 {
262 	uint total = pkttotlen(osh, p);
263 	uint pkt_off = 0, len = 0;
264 	uint8 *pdata = (uint8 *) PKTDATA(osh, p);
265 
266 	if (offset > total)
267 		return NULL;
268 
269 	for (; p; p = PKTNEXT(osh, p)) {
270 		pdata = (uint8 *) PKTDATA(osh, p);
271 		pkt_off = offset - len;
272 		len += PKTLEN(osh, p);
273 		if (len > offset)
274 			break;
275 	}
276 	return (uint8*) (pdata+pkt_off);
277 }
278 
279 
280 /* given a offset in pdata, find the pkt seg hdr */
281 void *
pktoffset(osl_t * osh,void * p,uint offset)282 pktoffset(osl_t *osh, void *p,  uint offset)
283 {
284 	uint total = pkttotlen(osh, p);
285 	uint len = 0;
286 
287 	if (offset > total)
288 		return NULL;
289 
290 	for (; p; p = PKTNEXT(osh, p)) {
291 		len += PKTLEN(osh, p);
292 		if (len > offset)
293 			break;
294 	}
295 	return p;
296 }
297 
298 #endif /* BCMDRIVER */
299 
300 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
301 const unsigned char bcm_ctype[] = {
302 
303 	_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,			/* 0-7 */
304 	_BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
305 	_BCM_C,	/* 8-15 */
306 	_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,			/* 16-23 */
307 	_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,			/* 24-31 */
308 	_BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,		/* 32-39 */
309 	_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,			/* 40-47 */
310 	_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,			/* 48-55 */
311 	_BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,			/* 56-63 */
312 	_BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
313 	_BCM_U|_BCM_X, _BCM_U, /* 64-71 */
314 	_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,			/* 72-79 */
315 	_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,			/* 80-87 */
316 	_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,			/* 88-95 */
317 	_BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
318 	_BCM_L|_BCM_X, _BCM_L, /* 96-103 */
319 	_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
320 	_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
321 	_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
322 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* 128-143 */
323 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* 144-159 */
324 	_BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
325 	_BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,	/* 160-175 */
326 	_BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
327 	_BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,	/* 176-191 */
328 	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
329 	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,	/* 192-207 */
330 	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
331 	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L,	/* 208-223 */
332 	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
333 	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,	/* 224-239 */
334 	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
335 	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
336 };
337 
338 ulong
bcm_strtoul(const char * cp,char ** endp,uint base)339 bcm_strtoul(const char *cp, char **endp, uint base)
340 {
341 	ulong result, last_result = 0, value;
342 	bool minus;
343 
344 	minus = FALSE;
345 
346 	while (bcm_isspace(*cp))
347 		cp++;
348 
349 	if (cp[0] == '+')
350 		cp++;
351 	else if (cp[0] == '-') {
352 		minus = TRUE;
353 		cp++;
354 	}
355 
356 	if (base == 0) {
357 		if (cp[0] == '0') {
358 			if ((cp[1] == 'x') || (cp[1] == 'X')) {
359 				base = 16;
360 				cp = &cp[2];
361 			} else {
362 				base = 8;
363 				cp = &cp[1];
364 			}
365 		} else
366 			base = 10;
367 	} else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
368 		cp = &cp[2];
369 	}
370 
371 	result = 0;
372 
373 	while (bcm_isxdigit(*cp) &&
374 	       (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
375 		result = result*base + value;
376 		/* Detected overflow */
377 		if (result < last_result && !minus) {
378 			if (endp) {
379 				/* Go to the end of current number */
380 				while (bcm_isxdigit(*cp)) {
381 					cp++;
382 				}
383 				*endp = DISCARD_QUAL(cp, char);
384 			}
385 			return (ulong)-1;
386 		}
387 		last_result = result;
388 		cp++;
389 	}
390 
391 	if (minus)
392 		result = (ulong)(-(long)result);
393 
394 	if (endp)
395 		*endp = DISCARD_QUAL(cp, char);
396 
397 	return (result);
398 }
399 
400 int
bcm_atoi(const char * s)401 bcm_atoi(const char *s)
402 {
403 	return (int)bcm_strtoul(s, NULL, 10);
404 }
405 
406 /* return pointer to location of substring 'needle' in 'haystack' */
407 char *
bcmstrstr(const char * haystack,const char * needle)408 bcmstrstr(const char *haystack, const char *needle)
409 {
410 	int len, nlen;
411 	int i;
412 
413 	if ((haystack == NULL) || (needle == NULL))
414 		return DISCARD_QUAL(haystack, char);
415 
416 	nlen = (int)strlen(needle);
417 	len = (int)strlen(haystack) - nlen + 1;
418 
419 	for (i = 0; i < len; i++)
420 		if (memcmp(needle, &haystack[i], nlen) == 0)
421 			return DISCARD_QUAL(&haystack[i], char);
422 	return (NULL);
423 }
424 
425 char *
bcmstrnstr(const char * s,uint s_len,const char * substr,uint substr_len)426 bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len)
427 {
428 	for (; s_len >= substr_len; s++, s_len--)
429 		if (strncmp(s, substr, substr_len) == 0)
430 			return DISCARD_QUAL(s, char);
431 
432 	return NULL;
433 }
434 
435 char *
bcmstrcat(char * dest,const char * src)436 bcmstrcat(char *dest, const char *src)
437 {
438 	char *p;
439 
440 	p = dest + strlen(dest);
441 
442 	while ((*p++ = *src++) != '\0')
443 		;
444 
445 	return (dest);
446 }
447 
448 char *
bcmstrncat(char * dest,const char * src,uint size)449 bcmstrncat(char *dest, const char *src, uint size)
450 {
451 	char *endp;
452 	char *p;
453 
454 	p = dest + strlen(dest);
455 	endp = p + size;
456 
457 	while (p != endp && (*p++ = *src++) != '\0')
458 		;
459 
460 	return (dest);
461 }
462 
463 
464 /****************************************************************************
465 * Function:   bcmstrtok
466 *
467 * Purpose:
468 *  Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
469 *  but allows strToken() to be used by different strings or callers at the same
470 *  time. Each call modifies '*string' by substituting a NULL character for the
471 *  first delimiter that is encountered, and updates 'string' to point to the char
472 *  after the delimiter. Leading delimiters are skipped.
473 *
474 * Parameters:
475 *  string      (mod) Ptr to string ptr, updated by token.
476 *  delimiters  (in)  Set of delimiter characters.
477 *  tokdelim    (out) Character that delimits the returned token. (May
478 *                    be set to NULL if token delimiter is not required).
479 *
480 * Returns:  Pointer to the next token found. NULL when no more tokens are found.
481 *****************************************************************************
482 */
483 char *
bcmstrtok(char ** string,const char * delimiters,char * tokdelim)484 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
485 {
486 	unsigned char *str;
487 	unsigned long map[8];
488 	int count;
489 	char *nextoken;
490 
491 	if (tokdelim != NULL) {
492 		/* Prime the token delimiter */
493 		*tokdelim = '\0';
494 	}
495 
496 	/* Clear control map */
497 	for (count = 0; count < 8; count++) {
498 		map[count] = 0;
499 	}
500 
501 	/* Set bits in delimiter table */
502 	do {
503 		map[*delimiters >> 5] |= (1 << (*delimiters & 31));
504 	}
505 	while (*delimiters++);
506 
507 	str = (unsigned char*)*string;
508 
509 	/* Find beginning of token (skip over leading delimiters). Note that
510 	 * there is no token iff this loop sets str to point to the terminal
511 	 * null (*str == '\0')
512 	 */
513 	while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
514 		str++;
515 	}
516 
517 	nextoken = (char*)str;
518 
519 	/* Find the end of the token. If it is not the end of the string,
520 	 * put a null there.
521 	 */
522 	for (; *str; str++) {
523 		if (map[*str >> 5] & (1 << (*str & 31))) {
524 			if (tokdelim != NULL) {
525 				*tokdelim = *str;
526 			}
527 
528 			*str++ = '\0';
529 			break;
530 		}
531 	}
532 
533 	*string = (char*)str;
534 
535 	/* Determine if a token has been found. */
536 	if (nextoken == (char *) str) {
537 		return NULL;
538 	}
539 	else {
540 		return nextoken;
541 	}
542 }
543 
544 
545 #define xToLower(C) \
546 	((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
547 
548 
549 /****************************************************************************
550 * Function:   bcmstricmp
551 *
552 * Purpose:    Compare to strings case insensitively.
553 *
554 * Parameters: s1 (in) First string to compare.
555 *             s2 (in) Second string to compare.
556 *
557 * Returns:    Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
558 *             t1 > t2, when ignoring case sensitivity.
559 *****************************************************************************
560 */
561 int
bcmstricmp(const char * s1,const char * s2)562 bcmstricmp(const char *s1, const char *s2)
563 {
564 	char dc, sc;
565 
566 	while (*s2 && *s1) {
567 		dc = xToLower(*s1);
568 		sc = xToLower(*s2);
569 		if (dc < sc) return -1;
570 		if (dc > sc) return 1;
571 		s1++;
572 		s2++;
573 	}
574 
575 	if (*s1 && !*s2) return 1;
576 	if (!*s1 && *s2) return -1;
577 	return 0;
578 }
579 
580 
581 /****************************************************************************
582 * Function:   bcmstrnicmp
583 *
584 * Purpose:    Compare to strings case insensitively, upto a max of 'cnt'
585 *             characters.
586 *
587 * Parameters: s1  (in) First string to compare.
588 *             s2  (in) Second string to compare.
589 *             cnt (in) Max characters to compare.
590 *
591 * Returns:    Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
592 *             t1 > t2, when ignoring case sensitivity.
593 *****************************************************************************
594 */
595 int
bcmstrnicmp(const char * s1,const char * s2,int cnt)596 bcmstrnicmp(const char* s1, const char* s2, int cnt)
597 {
598 	char dc, sc;
599 
600 	while (*s2 && *s1 && cnt) {
601 		dc = xToLower(*s1);
602 		sc = xToLower(*s2);
603 		if (dc < sc) return -1;
604 		if (dc > sc) return 1;
605 		s1++;
606 		s2++;
607 		cnt--;
608 	}
609 
610 	if (!cnt) return 0;
611 	if (*s1 && !*s2) return 1;
612 	if (!*s1 && *s2) return -1;
613 	return 0;
614 }
615 
616 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
617 int
bcm_ether_atoe(const char * p,struct ether_addr * ea)618 bcm_ether_atoe(const char *p, struct ether_addr *ea)
619 {
620 	int i = 0;
621 	char *ep;
622 
623 	for (;;) {
624 		ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
625 		p = ep;
626 		if (!*p++ || i == 6)
627 			break;
628 	}
629 
630 	return (i == 6);
631 }
632 
633 int
bcm_atoipv4(const char * p,struct ipv4_addr * ip)634 bcm_atoipv4(const char *p, struct ipv4_addr *ip)
635 {
636 
637 	int i = 0;
638 	char *c;
639 	for (;;) {
640 		ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0);
641 		if (*c++ != '.' || i == IPV4_ADDR_LEN)
642 			break;
643 		p = c;
644 	}
645 	return (i == IPV4_ADDR_LEN);
646 }
647 #endif	/* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
648 
649 
650 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
651 /* registry routine buffer preparation utility functions:
652  * parameter order is like strncpy, but returns count
653  * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
654  */
655 ulong
wchar2ascii(char * abuf,ushort * wbuf,ushort wbuflen,ulong abuflen)656 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
657 {
658 	ulong copyct = 1;
659 	ushort i;
660 
661 	if (abuflen == 0)
662 		return 0;
663 
664 	/* wbuflen is in bytes */
665 	wbuflen /= sizeof(ushort);
666 
667 	for (i = 0; i < wbuflen; ++i) {
668 		if (--abuflen == 0)
669 			break;
670 		*abuf++ = (char) *wbuf++;
671 		++copyct;
672 	}
673 	*abuf = '\0';
674 
675 	return copyct;
676 }
677 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
678 
679 char *
bcm_ether_ntoa(const struct ether_addr * ea,char * buf)680 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
681 {
682 	static const char hex[] =
683 	  {
684 		  '0', '1', '2', '3', '4', '5', '6', '7',
685 		  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
686 	  };
687 	const uint8 *octet = ea->octet;
688 	char *p = buf;
689 	int i;
690 
691 	for (i = 0; i < 6; i++, octet++) {
692 		*p++ = hex[(*octet >> 4) & 0xf];
693 		*p++ = hex[*octet & 0xf];
694 		*p++ = ':';
695 	}
696 
697 	*(p-1) = '\0';
698 
699 	return (buf);
700 }
701 
702 char *
bcm_ip_ntoa(struct ipv4_addr * ia,char * buf)703 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
704 {
705 	snprintf(buf, 16, "%d.%d.%d.%d",
706 	         ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
707 	return (buf);
708 }
709 
710 char *
bcm_ipv6_ntoa(void * ipv6,char * buf)711 bcm_ipv6_ntoa(void *ipv6, char *buf)
712 {
713 	/* Implementing RFC 5952 Sections 4 + 5 */
714 	/* Not thoroughly tested */
715 	uint16 tmp[8];
716 	uint16 *a = &tmp[0];
717 	char *p = buf;
718 	int i, i_max = -1, cnt = 0, cnt_max = 1;
719 	uint8 *a4 = NULL;
720 	memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
721 
722 	for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
723 		if (a[i]) {
724 			if (cnt > cnt_max) {
725 				cnt_max = cnt;
726 				i_max = i - cnt;
727 			}
728 			cnt = 0;
729 		} else
730 			cnt++;
731 	}
732 	if (cnt > cnt_max) {
733 		cnt_max = cnt;
734 		i_max = i - cnt;
735 	}
736 	if (i_max == 0 &&
737 		/* IPv4-translated: ::ffff:0:a.b.c.d */
738 		((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
739 		/* IPv4-mapped: ::ffff:a.b.c.d */
740 		(cnt_max == 5 && a[5] == 0xffff)))
741 		a4 = (uint8*) (a + 6);
742 
743 	for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
744 		if ((uint8*) (a + i) == a4) {
745 			snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
746 			break;
747 		} else if (i == i_max) {
748 			*p++ = ':';
749 			i += cnt_max - 1;
750 			p[0] = ':';
751 			p[1] = '\0';
752 		} else {
753 			if (i)
754 				*p++ = ':';
755 			p += snprintf(p, 8, "%x", ntoh16(a[i]));
756 		}
757 	}
758 
759 	return buf;
760 }
761 #ifdef BCMDRIVER
762 
763 void
bcm_mdelay(uint ms)764 bcm_mdelay(uint ms)
765 {
766 	uint i;
767 
768 	for (i = 0; i < ms; i++) {
769 		OSL_DELAY(1000);
770 	}
771 }
772 
773 
774 
775 
776 
777 #if defined(DHD_DEBUG)
778 /* pretty hex print a pkt buffer chain */
779 void
prpkt(const char * msg,osl_t * osh,void * p0)780 prpkt(const char *msg, osl_t *osh, void *p0)
781 {
782 	void *p;
783 
784 	if (msg && (msg[0] != '\0'))
785 		printf("%s:\n", msg);
786 
787 	for (p = p0; p; p = PKTNEXT(osh, p))
788 		prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
789 }
790 #endif
791 
792 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
793  * Also updates the inplace vlan tag if requested.
794  * For debugging, it returns an indication of what it did.
795  */
796 uint BCMFASTPATH
pktsetprio(void * pkt,bool update_vtag)797 pktsetprio(void *pkt, bool update_vtag)
798 {
799 	struct ether_header *eh;
800 	struct ethervlan_header *evh;
801 	uint8 *pktdata;
802 	int priority = 0;
803 	int rc = 0;
804 
805 	pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
806 	ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
807 
808 	eh = (struct ether_header *) pktdata;
809 
810 	if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
811 		uint16 vlan_tag;
812 		int vlan_prio, dscp_prio = 0;
813 
814 		evh = (struct ethervlan_header *)eh;
815 
816 		vlan_tag = ntoh16(evh->vlan_tag);
817 		vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
818 
819 		if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
820 			(evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
821 			uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
822 			uint8 tos_tc = IP_TOS46(ip_body);
823 			dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
824 		}
825 
826 		/* DSCP priority gets precedence over 802.1P (vlan tag) */
827 		if (dscp_prio != 0) {
828 			priority = dscp_prio;
829 			rc |= PKTPRIO_VDSCP;
830 		} else {
831 			priority = vlan_prio;
832 			rc |= PKTPRIO_VLAN;
833 		}
834 		/*
835 		 * If the DSCP priority is not the same as the VLAN priority,
836 		 * then overwrite the priority field in the vlan tag, with the
837 		 * DSCP priority value. This is required for Linux APs because
838 		 * the VLAN driver on Linux, overwrites the skb->priority field
839 		 * with the priority value in the vlan tag
840 		 */
841 		if (update_vtag && (priority != vlan_prio)) {
842 			vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
843 			vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
844 			evh->vlan_tag = hton16(vlan_tag);
845 			rc |= PKTPRIO_UPD;
846 		}
847 #if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING)
848 	} else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
849 		priority = PRIO_8021D_NC;
850 		rc = PKTPRIO_DSCP;
851 #endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */
852 	} else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
853 		(eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
854 		uint8 *ip_body = pktdata + sizeof(struct ether_header);
855 		uint8 tos_tc = IP_TOS46(ip_body);
856 		uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
857 		switch (dscp) {
858 		case DSCP_EF:
859 			priority = PRIO_8021D_VO;
860 			break;
861 		case DSCP_AF31:
862 		case DSCP_AF32:
863 		case DSCP_AF33:
864 			priority = PRIO_8021D_CL;
865 			break;
866 		case DSCP_AF21:
867 		case DSCP_AF22:
868 		case DSCP_AF23:
869 		case DSCP_AF11:
870 		case DSCP_AF12:
871 		case DSCP_AF13:
872 			priority = PRIO_8021D_EE;
873 			break;
874 		default:
875 			priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
876 			break;
877 		}
878 
879 		rc |= PKTPRIO_DSCP;
880 	}
881 
882 	ASSERT(priority >= 0 && priority <= MAXPRIO);
883 	PKTSETPRIO(pkt, priority);
884 	return (rc | priority);
885 }
886 
887 /* lookup user priority for specified DSCP */
888 static uint8
dscp2up(uint8 * up_table,uint8 dscp)889 dscp2up(uint8 *up_table, uint8 dscp)
890 {
891 	uint8 user_priority = 255;
892 
893 	/* lookup up from table if parameters valid */
894 	if (up_table != NULL && dscp < UP_TABLE_MAX) {
895 		user_priority = up_table[dscp];
896 	}
897 
898 	/* 255 is unused value so return up from dscp */
899 	if (user_priority == 255) {
900 		user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
901 	}
902 
903 	return user_priority;
904 }
905 
906 /* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
907 uint BCMFASTPATH
pktsetprio_qms(void * pkt,uint8 * up_table,bool update_vtag)908 pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag)
909 {
910 	if (up_table) {
911 		uint8 *pktdata;
912 		uint pktlen;
913 		uint8 dscp;
914 		uint user_priority = 0;
915 		uint rc = 0;
916 
917 		pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
918 		pktlen = PKTLEN(OSH_NULL, pkt);
919 
920 		if (pktgetdscp(pktdata, pktlen, &dscp)) {
921 			rc = PKTPRIO_DSCP;
922 			user_priority = dscp2up(up_table, dscp);
923 			PKTSETPRIO(pkt, user_priority);
924 		}
925 
926 		return (rc | user_priority);
927 	} else {
928 		return pktsetprio(pkt, update_vtag);
929 	}
930 }
931 
932 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
933  */
934 bool BCMFASTPATH
pktgetdscp(uint8 * pktdata,uint pktlen,uint8 * dscp)935 pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
936 {
937 	struct ether_header *eh;
938 	struct ethervlan_header *evh;
939 	uint8 *ip_body;
940 	bool rc = FALSE;
941 
942 	/* minimum length is ether header and IP header */
943 	if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
944 		return FALSE;
945 
946 	eh = (struct ether_header *) pktdata;
947 
948 	if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
949 		ip_body = pktdata + sizeof(struct ether_header);
950 		*dscp = IP_DSCP46(ip_body);
951 		rc = TRUE;
952 	}
953 	else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
954 		evh = (struct ethervlan_header *)eh;
955 
956 		/* minimum length is ethervlan header and IP header */
957 		if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
958 			evh->ether_type == HTON16(ETHER_TYPE_IP)) {
959 			ip_body = pktdata + sizeof(struct ethervlan_header);
960 			*dscp = IP_DSCP46(ip_body);
961 			rc = TRUE;
962 		}
963 	}
964 
965 	return rc;
966 }
967 
968 /* Add to adjust the 802.1x priority */
969 void
pktset8021xprio(void * pkt,int prio)970 pktset8021xprio(void *pkt, int prio)
971 {
972 	struct ether_header *eh;
973 	uint8 *pktdata;
974 	if(prio == PKTPRIO(pkt))
975 		return;
976 	pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
977 	ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
978 	eh = (struct ether_header *) pktdata;
979 	if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
980 		ASSERT(prio >= 0 && prio <= MAXPRIO);
981 		PKTSETPRIO(pkt, prio);
982 	}
983 }
984 
985 /* usr_prio range from low to high with usr_prio value */
986 static bool
up_table_set(uint8 * up_table,uint8 usr_prio,uint8 low,uint8 high)987 up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high)
988 {
989 	int i;
990 
991 	if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) {
992 		return FALSE;
993 	}
994 
995 	for (i = low; i <= high; i++) {
996 		up_table[i] = usr_prio;
997 	}
998 
999 	return TRUE;
1000 }
1001 
1002 /* set user priority table */
1003 int BCMFASTPATH
wl_set_up_table(uint8 * up_table,bcm_tlv_t * qos_map_ie)1004 wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie)
1005 {
1006 	uint8 len;
1007 
1008 	if (up_table == NULL || qos_map_ie == NULL) {
1009 		return BCME_ERROR;
1010 	}
1011 
1012 	/* clear table to check table was set or not */
1013 	memset(up_table, 0xff, UP_TABLE_MAX);
1014 
1015 	/* length of QoS Map IE must be 16+n*2, n is number of exceptions */
1016 	if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID &&
1017 			(len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH &&
1018 			(len % 2) == 0) {
1019 		uint8 *except_ptr = (uint8 *)qos_map_ie->data;
1020 		uint8 except_len = len - QOS_MAP_FIXED_LENGTH;
1021 		uint8 *range_ptr = except_ptr + except_len;
1022 		int i;
1023 
1024 		/* fill in ranges */
1025 		for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) {
1026 			uint8 low = range_ptr[i];
1027 			uint8 high = range_ptr[i + 1];
1028 			if (low == 255 && high == 255) {
1029 				continue;
1030 			}
1031 
1032 			if (!up_table_set(up_table, i / 2, low, high)) {
1033 				/* clear the table on failure */
1034 				memset(up_table, 0xff, UP_TABLE_MAX);
1035 				return BCME_ERROR;
1036 			}
1037 		}
1038 
1039 		/* update exceptions */
1040 		for (i = 0; i < except_len; i += 2) {
1041 			uint8 dscp = except_ptr[i];
1042 			uint8 usr_prio = except_ptr[i+1];
1043 
1044 			/* exceptions with invalid dscp/usr_prio are ignored */
1045 			up_table_set(up_table, usr_prio, dscp, dscp);
1046 		}
1047 	}
1048 
1049 	return BCME_OK;
1050 }
1051 
1052 /* The 0.5KB string table is not removed by compiler even though it's unused */
1053 
1054 static char bcm_undeferrstr[32];
1055 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1056 
1057 /* Convert the error codes into related error strings  */
1058 const char *
bcmerrorstr(int bcmerror)1059 bcmerrorstr(int bcmerror)
1060 {
1061 	/* check if someone added a bcmerror code but forgot to add errorstring */
1062 	ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
1063 
1064 	if (bcmerror > 0 || bcmerror < BCME_LAST) {
1065 		snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
1066 		return bcm_undeferrstr;
1067 	}
1068 
1069 	ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1070 
1071 	return bcmerrorstrtable[-bcmerror];
1072 }
1073 
1074 
1075 /* iovar table lookup */
1076 /* could mandate sorted tables and do a binary search */
1077 const bcm_iovar_t*
bcm_iovar_lookup(const bcm_iovar_t * table,const char * name)1078 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1079 {
1080 	const bcm_iovar_t *vi;
1081 	const char *lookup_name;
1082 
1083 	/* skip any ':' delimited option prefixes */
1084 	lookup_name = strrchr(name, ':');
1085 	if (lookup_name != NULL)
1086 		lookup_name++;
1087 	else
1088 		lookup_name = name;
1089 
1090 	ASSERT(table != NULL);
1091 
1092 	for (vi = table; vi->name; vi++) {
1093 		if (!strcmp(vi->name, lookup_name))
1094 			return vi;
1095 	}
1096 	/* ran to end of table */
1097 
1098 	return NULL; /* var name not found */
1099 }
1100 
1101 int
bcm_iovar_lencheck(const bcm_iovar_t * vi,void * arg,int len,bool set)1102 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1103 {
1104 	int bcmerror = 0;
1105 	BCM_REFERENCE(arg);
1106 
1107 	/* length check on io buf */
1108 	switch (vi->type) {
1109 	case IOVT_BOOL:
1110 	case IOVT_INT8:
1111 	case IOVT_INT16:
1112 	case IOVT_INT32:
1113 	case IOVT_UINT8:
1114 	case IOVT_UINT16:
1115 	case IOVT_UINT32:
1116 		/* all integers are int32 sized args at the ioctl interface */
1117 		if (len < (int)sizeof(int)) {
1118 			bcmerror = BCME_BUFTOOSHORT;
1119 		}
1120 		break;
1121 
1122 	case IOVT_BUFFER:
1123 		/* buffer must meet minimum length requirement */
1124 		if (len < vi->minlen) {
1125 			bcmerror = BCME_BUFTOOSHORT;
1126 		}
1127 		break;
1128 
1129 	case IOVT_VOID:
1130 		if (!set) {
1131 			/* Cannot return nil... */
1132 			bcmerror = BCME_UNSUPPORTED;
1133 		} else if (len) {
1134 			/* Set is an action w/o parameters */
1135 			bcmerror = BCME_BUFTOOLONG;
1136 		}
1137 		break;
1138 
1139 	default:
1140 		/* unknown type for length check in iovar info */
1141 		ASSERT(0);
1142 		bcmerror = BCME_UNSUPPORTED;
1143 	}
1144 
1145 	return bcmerror;
1146 }
1147 
1148 #endif	/* BCMDRIVER */
1149 
1150 #ifdef BCM_OBJECT_TRACE
1151 
1152 #define BCM_OBJECT_MERGE_SAME_OBJ	0
1153 
1154 /* some place may add / remove the object to trace list for Linux: */
1155 /* add:    osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */
1156 /* remove: osl_pktfree dev_kfree_skb netif_rx */
1157 
1158 #define BCM_OBJDBG_COUNT          (1024 * 100)
1159 static spinlock_t dbgobj_lock;
1160 #define	BCM_OBJDBG_LOCK_INIT()    spin_lock_init(&dbgobj_lock)
1161 #define	BCM_OBJDBG_LOCK_DESTROY()
1162 #define	BCM_OBJDBG_LOCK           spin_lock_irqsave
1163 #define	BCM_OBJDBG_UNLOCK         spin_unlock_irqrestore
1164 
1165 #define BCM_OBJDBG_ADDTOHEAD      0
1166 #define BCM_OBJDBG_ADDTOTAIL      1
1167 
1168 #define BCM_OBJDBG_CALLER_LEN     32
1169 struct bcm_dbgobj {
1170 	struct bcm_dbgobj *prior;
1171 	struct bcm_dbgobj *next;
1172 	uint32 flag;
1173 	void   *obj;
1174 	uint32 obj_sn;
1175 	uint32 obj_state;
1176 	uint32 line;
1177 	char   caller[BCM_OBJDBG_CALLER_LEN];
1178 };
1179 
1180 static struct bcm_dbgobj *dbgobj_freehead = NULL;
1181 static struct bcm_dbgobj *dbgobj_freetail = NULL;
1182 static struct bcm_dbgobj *dbgobj_objhead = NULL;
1183 static struct bcm_dbgobj *dbgobj_objtail = NULL;
1184 
1185 static uint32 dbgobj_sn = 0;
1186 static int dbgobj_count = 0;
1187 static struct bcm_dbgobj bcm_dbg_objs[BCM_OBJDBG_COUNT];
1188 
1189 void
bcm_object_trace_init(void)1190 bcm_object_trace_init(void)
1191 {
1192 	int i = 0;
1193 	BCM_OBJDBG_LOCK_INIT();
1194 	memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT);
1195 	dbgobj_freehead = &bcm_dbg_objs[0];
1196 	dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1];
1197 
1198 	for (i = 0; i < BCM_OBJDBG_COUNT; ++i) {
1199 		bcm_dbg_objs[i].next = (i == (BCM_OBJDBG_COUNT - 1)) ?
1200 			dbgobj_freehead : &bcm_dbg_objs[i + 1];
1201 		bcm_dbg_objs[i].prior = (i == 0) ?
1202 			dbgobj_freetail : &bcm_dbg_objs[i - 1];
1203 	}
1204 }
1205 
1206 void
bcm_object_trace_deinit(void)1207 bcm_object_trace_deinit(void)
1208 {
1209 	if (dbgobj_objhead || dbgobj_objtail) {
1210 		printf("%s: not all objects are released\n", __FUNCTION__);
1211 		ASSERT(0);
1212 	}
1213 	BCM_OBJDBG_LOCK_DESTROY();
1214 }
1215 
1216 static void
bcm_object_rm_list(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj)1217 bcm_object_rm_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
1218 	struct bcm_dbgobj *dbgobj)
1219 {
1220 	if ((dbgobj == *head) && (dbgobj == *tail)) {
1221 		*head = NULL;
1222 		*tail = NULL;
1223 	} else if (dbgobj == *head) {
1224 		*head = (*head)->next;
1225 	} else if (dbgobj == *tail) {
1226 		*tail = (*tail)->prior;
1227 	}
1228 	dbgobj->next->prior = dbgobj->prior;
1229 	dbgobj->prior->next = dbgobj->next;
1230 }
1231 
1232 static void
bcm_object_add_list(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj,int addtotail)1233 bcm_object_add_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
1234 	struct bcm_dbgobj *dbgobj, int addtotail)
1235 {
1236 	if (!(*head) && !(*tail)) {
1237 		*head = dbgobj;
1238 		*tail = dbgobj;
1239 		dbgobj->next = dbgobj;
1240 		dbgobj->prior = dbgobj;
1241 	} else if ((*head) && (*tail)) {
1242 		(*tail)->next = dbgobj;
1243 		(*head)->prior = dbgobj;
1244 		dbgobj->next = *head;
1245 		dbgobj->prior = *tail;
1246 		if (addtotail == BCM_OBJDBG_ADDTOTAIL)
1247 			*tail = dbgobj;
1248 		else
1249 			*head = dbgobj;
1250 	} else {
1251 		ASSERT(0); /* can't be this case */
1252 	}
1253 }
1254 
1255 static INLINE void
bcm_object_movetoend(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj,int movetotail)1256 bcm_object_movetoend(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
1257 	struct bcm_dbgobj *dbgobj, int movetotail)
1258 {
1259 	if ((*head) && (*tail)) {
1260 		if (movetotail == BCM_OBJDBG_ADDTOTAIL) {
1261 			if (dbgobj != (*tail)) {
1262 				bcm_object_rm_list(head, tail, dbgobj);
1263 				bcm_object_add_list(head, tail, dbgobj, movetotail);
1264 			}
1265 		} else {
1266 			if (dbgobj != (*head)) {
1267 				bcm_object_rm_list(head, tail, dbgobj);
1268 				bcm_object_add_list(head, tail, dbgobj, movetotail);
1269 			}
1270 		}
1271 	} else {
1272 		ASSERT(0); /* can't be this case */
1273 	}
1274 }
1275 
1276 void
bcm_object_trace_opr(void * obj,uint32 opt,const char * caller,int line)1277 bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line)
1278 {
1279 	struct bcm_dbgobj *dbgobj;
1280 	unsigned long flags;
1281 
1282 	BCM_REFERENCE(flags);
1283 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1284 
1285 	if (opt == BCM_OBJDBG_ADD_PKT ||
1286 		opt == BCM_OBJDBG_ADD) {
1287 		dbgobj = dbgobj_objtail;
1288 		while (dbgobj) {
1289 			if (dbgobj->obj == obj) {
1290 				printf("%s: obj %p allocated from %s(%d),"
1291 					" allocate again from %s(%d)\n",
1292 					__FUNCTION__, dbgobj->obj,
1293 					dbgobj->caller, dbgobj->line,
1294 					caller, line);
1295 				ASSERT(0);
1296 				goto EXIT;
1297 			}
1298 			dbgobj = dbgobj->prior;
1299 			if (dbgobj == dbgobj_objtail)
1300 				break;
1301 		}
1302 
1303 #if BCM_OBJECT_MERGE_SAME_OBJ
1304 		dbgobj = dbgobj_freetail;
1305 		while (dbgobj) {
1306 			if (dbgobj->obj == obj) {
1307 				goto FREED_ENTRY_FOUND;
1308 			}
1309 			dbgobj = dbgobj->prior;
1310 			if (dbgobj == dbgobj_freetail)
1311 				break;
1312 		}
1313 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
1314 
1315 		dbgobj = dbgobj_freehead;
1316 #if BCM_OBJECT_MERGE_SAME_OBJ
1317 FREED_ENTRY_FOUND:
1318 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
1319 		if (!dbgobj) {
1320 			printf("%s: already got %d objects ?????????????????????\n",
1321 				__FUNCTION__, BCM_OBJDBG_COUNT);
1322 			ASSERT(0);
1323 			goto EXIT;
1324 		}
1325 
1326 		bcm_object_rm_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj);
1327 		dbgobj->obj = obj;
1328 		strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
1329 		dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
1330 		dbgobj->line = line;
1331 		dbgobj->flag = 0;
1332 		if (opt == BCM_OBJDBG_ADD_PKT) {
1333 			dbgobj->obj_sn = dbgobj_sn++;
1334 			dbgobj->obj_state = 0;
1335 			/* first 4 bytes is pkt sn */
1336 			if (((unsigned long)PKTTAG(obj)) & 0x3)
1337 				printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj));
1338 			*(uint32*)PKTTAG(obj) = dbgobj->obj_sn;
1339 		}
1340 		bcm_object_add_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
1341 			BCM_OBJDBG_ADDTOTAIL);
1342 
1343 		dbgobj_count++;
1344 
1345 	} else if (opt == BCM_OBJDBG_REMOVE) {
1346 		dbgobj = dbgobj_objtail;
1347 		while (dbgobj) {
1348 			if (dbgobj->obj == obj) {
1349 				if (dbgobj->flag) {
1350 					printf("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n",
1351 						__FUNCTION__, obj, dbgobj->flag, caller, line);
1352 				}
1353 				bcm_object_rm_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj);
1354 				memset(dbgobj->caller, 0x00, BCM_OBJDBG_CALLER_LEN);
1355 				strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
1356 				dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
1357 				dbgobj->line = line;
1358 				bcm_object_add_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj,
1359 					BCM_OBJDBG_ADDTOTAIL);
1360 				dbgobj_count--;
1361 				goto EXIT;
1362 			}
1363 			dbgobj = dbgobj->prior;
1364 			if (dbgobj == dbgobj_objtail)
1365 				break;
1366 		}
1367 
1368 		dbgobj = dbgobj_freetail;
1369 		while (dbgobj && dbgobj->obj) {
1370 			if (dbgobj->obj == obj) {
1371 				printf("%s: obj %p already freed from from %s(%d),"
1372 					" try free again from %s(%d)\n",
1373 					__FUNCTION__, obj,
1374 					dbgobj->caller, dbgobj->line,
1375 					caller, line);
1376 				//ASSERT(0); /* release same obj more than one time? */
1377 				goto EXIT;
1378 			}
1379 			dbgobj = dbgobj->prior;
1380 			if (dbgobj == dbgobj_freetail)
1381 				break;
1382 		}
1383 
1384 		printf("%s: ################### release none-existing obj %p from %s(%d)\n",
1385 			__FUNCTION__, obj, caller, line);
1386 		//ASSERT(0); /* release same obj more than one time? */
1387 
1388 	}
1389 
1390 EXIT:
1391 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1392 	return;
1393 }
1394 
1395 void
bcm_object_trace_upd(void * obj,void * obj_new)1396 bcm_object_trace_upd(void *obj, void *obj_new)
1397 {
1398 	struct bcm_dbgobj *dbgobj;
1399 	unsigned long flags;
1400 
1401 	BCM_REFERENCE(flags);
1402 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1403 
1404 	dbgobj = dbgobj_objtail;
1405 	while (dbgobj) {
1406 		if (dbgobj->obj == obj) {
1407 			dbgobj->obj = obj_new;
1408 			if (dbgobj != dbgobj_objtail) {
1409 				bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1410 					dbgobj, BCM_OBJDBG_ADDTOTAIL);
1411 			}
1412 			goto EXIT;
1413 		}
1414 		dbgobj = dbgobj->prior;
1415 		if (dbgobj == dbgobj_objtail)
1416 			break;
1417 	}
1418 
1419 EXIT:
1420 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1421 	return;
1422 }
1423 
1424 void
bcm_object_trace_chk(void * obj,uint32 chksn,uint32 sn,const char * caller,int line)1425 bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn,
1426 	const char *caller, int line)
1427 {
1428 	struct bcm_dbgobj *dbgobj;
1429 	unsigned long flags;
1430 
1431 	BCM_REFERENCE(flags);
1432 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1433 
1434 	dbgobj = dbgobj_objtail;
1435 	while (dbgobj) {
1436 		if ((dbgobj->obj == obj) &&
1437 			((!chksn) || (dbgobj->obj_sn == sn))) {
1438 			if (dbgobj != dbgobj_objtail) {
1439 				bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1440 					dbgobj, BCM_OBJDBG_ADDTOTAIL);
1441 			}
1442 			goto EXIT;
1443 		}
1444 		dbgobj = dbgobj->prior;
1445 		if (dbgobj == dbgobj_objtail)
1446 			break;
1447 	}
1448 
1449 	dbgobj = dbgobj_freetail;
1450 	while (dbgobj) {
1451 		if ((dbgobj->obj == obj) &&
1452 			((!chksn) || (dbgobj->obj_sn == sn))) {
1453 			printf("%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n",
1454 				__FUNCTION__, caller, line,
1455 				dbgobj->obj, dbgobj->obj_sn, dbgobj->obj_state,
1456 				dbgobj->caller, dbgobj->line);
1457 			goto EXIT;
1458 		}
1459 		else if (dbgobj->obj == NULL) {
1460 			break;
1461 		}
1462 		dbgobj = dbgobj->prior;
1463 		if (dbgobj == dbgobj_freetail)
1464 			break;
1465 	}
1466 
1467 	printf("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n",
1468 		__FUNCTION__, obj, caller, line, chksn ? "yes" : "no", sn);
1469 	dbgobj = dbgobj_objtail;
1470 	while (dbgobj) {
1471 		printf("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n",
1472 				__FUNCTION__, caller, line,
1473 				dbgobj->obj, dbgobj->obj_sn, dbgobj->caller, dbgobj->line);
1474 		dbgobj = dbgobj->prior;
1475 		if (dbgobj == dbgobj_objtail)
1476 			break;
1477 	}
1478 
1479 EXIT:
1480 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1481 	return;
1482 }
1483 
1484 void
bcm_object_feature_set(void * obj,uint32 type,uint32 value)1485 bcm_object_feature_set(void *obj, uint32 type, uint32 value)
1486 {
1487 	struct bcm_dbgobj *dbgobj;
1488 	unsigned long flags;
1489 
1490 	BCM_REFERENCE(flags);
1491 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1492 
1493 	dbgobj = dbgobj_objtail;
1494 	while (dbgobj) {
1495 		if (dbgobj->obj == obj) {
1496 			if (type == BCM_OBJECT_FEATURE_FLAG) {
1497 				if (value & BCM_OBJECT_FEATURE_CLEAR)
1498 					dbgobj->flag &= ~(value);
1499 				else
1500 					dbgobj->flag |= (value);
1501 			} else if (type == BCM_OBJECT_FEATURE_PKT_STATE) {
1502 				dbgobj->obj_state = value;
1503 			}
1504 			if (dbgobj != dbgobj_objtail) {
1505 				bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1506 					dbgobj, BCM_OBJDBG_ADDTOTAIL);
1507 			}
1508 			goto EXIT;
1509 		}
1510 		dbgobj = dbgobj->prior;
1511 		if (dbgobj == dbgobj_objtail)
1512 			break;
1513 	}
1514 
1515 	printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
1516 	ASSERT(0);
1517 
1518 EXIT:
1519 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1520 	return;
1521 }
1522 
1523 int
bcm_object_feature_get(void * obj,uint32 type,uint32 value)1524 bcm_object_feature_get(void *obj, uint32 type, uint32 value)
1525 {
1526 	int rtn = 0;
1527 	struct bcm_dbgobj *dbgobj;
1528 	unsigned long flags;
1529 
1530 	BCM_REFERENCE(flags);
1531 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1532 
1533 	dbgobj = dbgobj_objtail;
1534 	while (dbgobj) {
1535 		if (dbgobj->obj == obj) {
1536 			if (type == BCM_OBJECT_FEATURE_FLAG) {
1537 				rtn = (dbgobj->flag & value) & (~BCM_OBJECT_FEATURE_CLEAR);
1538 			}
1539 			if (dbgobj != dbgobj_objtail) {
1540 				bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1541 					dbgobj, BCM_OBJDBG_ADDTOTAIL);
1542 			}
1543 			goto EXIT;
1544 		}
1545 		dbgobj = dbgobj->prior;
1546 		if (dbgobj == dbgobj_objtail)
1547 			break;
1548 	}
1549 
1550 	printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
1551 	ASSERT(0);
1552 
1553 EXIT:
1554 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1555 	return rtn;
1556 }
1557 
1558 #endif /* BCM_OBJECT_TRACE */
1559 
1560 uint8 *
bcm_write_tlv(int type,const void * data,int datalen,uint8 * dst)1561 bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst)
1562 {
1563 	uint8 *new_dst = dst;
1564 	bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst;
1565 
1566 	/* dst buffer should always be valid */
1567 	ASSERT(dst);
1568 
1569 	/* data len must be within valid range */
1570 	ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE));
1571 
1572 	/* source data buffer pointer should be valid, unless datalen is 0
1573 	 * meaning no data with this TLV
1574 	 */
1575 	ASSERT((data != NULL) || (datalen == 0));
1576 
1577 	/* only do work if the inputs are valid
1578 	 * - must have a dst to write to AND
1579 	 * - datalen must be within range AND
1580 	 * - the source data pointer must be non-NULL if datalen is non-zero
1581 	 * (this last condition detects datalen > 0 with a NULL data pointer)
1582 	 */
1583 	if ((dst != NULL) &&
1584 	    ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
1585 	    ((data != NULL) || (datalen == 0))) {
1586 
1587 	        /* write type, len fields */
1588 		dst_tlv->id = (uint8)type;
1589 	        dst_tlv->len = (uint8)datalen;
1590 
1591 		/* if data is present, copy to the output buffer and update
1592 		 * pointer to output buffer
1593 		 */
1594 		if (datalen > 0) {
1595 
1596 			memcpy(dst_tlv->data, data, datalen);
1597 		}
1598 
1599 		/* update the output destination poitner to point past
1600 		 * the TLV written
1601 		 */
1602 		new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
1603 	}
1604 
1605 	return (new_dst);
1606 }
1607 
1608 uint8 *
bcm_write_tlv_safe(int type,const void * data,int datalen,uint8 * dst,int dst_maxlen)1609 bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen)
1610 {
1611 	uint8 *new_dst = dst;
1612 
1613 	if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) {
1614 
1615 		/* if len + tlv hdr len is more than destlen, don't do anything
1616 		 * just return the buffer untouched
1617 		 */
1618 		if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) {
1619 
1620 			new_dst = bcm_write_tlv(type, data, datalen, dst);
1621 		}
1622 	}
1623 
1624 	return (new_dst);
1625 }
1626 
1627 uint8 *
bcm_copy_tlv(const void * src,uint8 * dst)1628 bcm_copy_tlv(const void *src, uint8 *dst)
1629 {
1630 	uint8 *new_dst = dst;
1631 	const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1632 	uint totlen;
1633 
1634 	ASSERT(dst && src);
1635 	if (dst && src) {
1636 
1637 		totlen = BCM_TLV_HDR_SIZE + src_tlv->len;
1638 		memcpy(dst, src_tlv, totlen);
1639 		new_dst = dst + totlen;
1640 	}
1641 
1642 	return (new_dst);
1643 }
1644 
1645 
bcm_copy_tlv_safe(const void * src,uint8 * dst,int dst_maxlen)1646 uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen)
1647 {
1648 	uint8 *new_dst = dst;
1649 	const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1650 
1651 	ASSERT(src);
1652 	if (src) {
1653 		if (bcm_valid_tlv(src_tlv, dst_maxlen)) {
1654 			new_dst = bcm_copy_tlv(src, dst);
1655 		}
1656 	}
1657 
1658 	return (new_dst);
1659 }
1660 
1661 
1662 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
1663 /*******************************************************************************
1664  * crc8
1665  *
1666  * Computes a crc8 over the input data using the polynomial:
1667  *
1668  *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
1669  *
1670  * The caller provides the initial value (either CRC8_INIT_VALUE
1671  * or the previous returned value) to allow for processing of
1672  * discontiguous blocks of data.  When generating the CRC the
1673  * caller is responsible for complementing the final return value
1674  * and inserting it into the byte stream.  When checking, a final
1675  * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1676  *
1677  * Reference: Dallas Semiconductor Application Note 27
1678  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1679  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1680  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1681  *
1682  * ****************************************************************************
1683  */
1684 
1685 static const uint8 crc8_table[256] = {
1686     0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1687     0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1688     0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1689     0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1690     0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1691     0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1692     0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1693     0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1694     0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1695     0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1696     0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1697     0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1698     0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1699     0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1700     0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1701     0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1702     0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1703     0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1704     0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1705     0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1706     0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1707     0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1708     0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1709     0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1710     0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1711     0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1712     0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1713     0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1714     0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1715     0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1716     0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1717     0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1718 };
1719 
1720 #define CRC_INNER_LOOP(n, c, x) \
1721 	(c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1722 
1723 uint8
hndcrc8(uint8 * pdata,uint nbytes,uint8 crc)1724 hndcrc8(
1725 	uint8 *pdata,	/* pointer to array of data to process */
1726 	uint  nbytes,	/* number of input data bytes to process */
1727 	uint8 crc	/* either CRC8_INIT_VALUE or previous return value */
1728 )
1729 {
1730 	/* hard code the crc loop instead of using CRC_INNER_LOOP macro
1731 	 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1732 	 */
1733 	while (nbytes-- > 0)
1734 		crc = crc8_table[(crc ^ *pdata++) & 0xff];
1735 
1736 	return crc;
1737 }
1738 
1739 /*******************************************************************************
1740  * crc16
1741  *
1742  * Computes a crc16 over the input data using the polynomial:
1743  *
1744  *       x^16 + x^12 +x^5 + 1
1745  *
1746  * The caller provides the initial value (either CRC16_INIT_VALUE
1747  * or the previous returned value) to allow for processing of
1748  * discontiguous blocks of data.  When generating the CRC the
1749  * caller is responsible for complementing the final return value
1750  * and inserting it into the byte stream.  When checking, a final
1751  * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1752  *
1753  * Reference: Dallas Semiconductor Application Note 27
1754  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1755  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1756  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1757  *
1758  * ****************************************************************************
1759  */
1760 
1761 static const uint16 crc16_table[256] = {
1762     0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1763     0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1764     0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1765     0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1766     0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1767     0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1768     0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1769     0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1770     0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1771     0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1772     0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1773     0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1774     0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1775     0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1776     0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1777     0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1778     0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1779     0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1780     0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1781     0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1782     0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1783     0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1784     0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1785     0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1786     0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1787     0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1788     0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1789     0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1790     0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1791     0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1792     0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1793     0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1794 };
1795 
1796 uint16
hndcrc16(uint8 * pdata,uint nbytes,uint16 crc)1797 hndcrc16(
1798     uint8 *pdata,  /* pointer to array of data to process */
1799     uint nbytes, /* number of input data bytes to process */
1800     uint16 crc     /* either CRC16_INIT_VALUE or previous return value */
1801 )
1802 {
1803 	while (nbytes-- > 0)
1804 		CRC_INNER_LOOP(16, crc, *pdata++);
1805 	return crc;
1806 }
1807 
1808 static const uint32 crc32_table[256] = {
1809     0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1810     0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1811     0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1812     0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1813     0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1814     0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1815     0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1816     0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1817     0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1818     0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1819     0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1820     0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1821     0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1822     0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1823     0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1824     0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1825     0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1826     0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1827     0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1828     0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1829     0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1830     0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1831     0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1832     0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1833     0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1834     0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1835     0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1836     0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1837     0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1838     0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1839     0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1840     0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1841     0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1842     0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1843     0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1844     0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1845     0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1846     0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1847     0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1848     0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1849     0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1850     0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1851     0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1852     0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1853     0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1854     0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1855     0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1856     0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1857     0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1858     0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1859     0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1860     0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1861     0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1862     0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1863     0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1864     0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1865     0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1866     0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1867     0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1868     0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1869     0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1870     0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1871     0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1872     0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1873 };
1874 
1875 /*
1876  * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
1877  * accumulating over multiple pieces.
1878  */
1879 uint32
hndcrc32(uint8 * pdata,uint nbytes,uint32 crc)1880 hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
1881 {
1882 	uint8 *pend;
1883 	pend = pdata + nbytes;
1884 	while (pdata < pend)
1885 		CRC_INNER_LOOP(32, crc, *pdata++);
1886 
1887 	return crc;
1888 }
1889 
1890 #ifdef notdef
1891 #define CLEN 	1499 	/*  CRC Length */
1892 #define CBUFSIZ 	(CLEN+4)
1893 #define CNBUFS		5 /* # of bufs */
1894 
1895 void
testcrc32(void)1896 testcrc32(void)
1897 {
1898 	uint j, k, l;
1899 	uint8 *buf;
1900 	uint len[CNBUFS];
1901 	uint32 crcr;
1902 	uint32 crc32tv[CNBUFS] =
1903 		{0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1904 
1905 	ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1906 
1907 	/* step through all possible alignments */
1908 	for (l = 0; l <= 4; l++) {
1909 		for (j = 0; j < CNBUFS; j++) {
1910 			len[j] = CLEN;
1911 			for (k = 0; k < len[j]; k++)
1912 				*(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1913 		}
1914 
1915 		for (j = 0; j < CNBUFS; j++) {
1916 			crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1917 			ASSERT(crcr == crc32tv[j]);
1918 		}
1919 	}
1920 
1921 	MFREE(buf, CBUFSIZ*CNBUFS);
1922 	return;
1923 }
1924 #endif /* notdef */
1925 
1926 /*
1927  * Advance from the current 1-byte tag/1-byte length/variable-length value
1928  * triple, to the next, returning a pointer to the next.
1929  * If the current or next TLV is invalid (does not fit in given buffer length),
1930  * NULL is returned.
1931  * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1932  * by the TLV parameter's length if it is valid.
1933  */
1934 bcm_tlv_t *
bcm_next_tlv(bcm_tlv_t * elt,int * buflen)1935 bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1936 {
1937 	int len;
1938 
1939 	/* validate current elt */
1940 	if (!bcm_valid_tlv(elt, *buflen)) {
1941 		return NULL;
1942 	}
1943 
1944 	/* advance to next elt */
1945 	len = elt->len;
1946 	elt = (bcm_tlv_t*)(elt->data + len);
1947 	*buflen -= (TLV_HDR_LEN + len);
1948 
1949 	/* validate next elt */
1950 	if (!bcm_valid_tlv(elt, *buflen)) {
1951 		return NULL;
1952 	}
1953 
1954 	return elt;
1955 }
1956 
1957 /*
1958  * Traverse a string of 1-byte tag/1-byte length/variable-length value
1959  * triples, returning a pointer to the substring whose first element
1960  * matches tag
1961  */
1962 bcm_tlv_t *
bcm_parse_tlvs(void * buf,int buflen,uint key)1963 bcm_parse_tlvs(void *buf, int buflen, uint key)
1964 {
1965 	bcm_tlv_t *elt;
1966 	int totlen;
1967 
1968 	if ((elt = (bcm_tlv_t*)buf) == NULL) {
1969 		return NULL;
1970 	}
1971 	totlen = buflen;
1972 
1973 	/* find tagged parameter */
1974 	while (totlen >= TLV_HDR_LEN) {
1975 		int len = elt->len;
1976 
1977 		/* validate remaining totlen */
1978 		if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
1979 
1980 			return (elt);
1981 		}
1982 
1983 		elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
1984 		totlen -= (len + TLV_HDR_LEN);
1985 	}
1986 
1987 	return NULL;
1988 }
1989 
1990 bcm_tlv_t *
bcm_parse_tlvs_dot11(void * buf,int buflen,uint key,bool id_ext)1991 bcm_parse_tlvs_dot11(void *buf, int buflen, uint key, bool id_ext)
1992 {
1993 	bcm_tlv_t *elt;
1994 	int totlen;
1995 
1996 	elt = (bcm_tlv_t*)buf;
1997 	totlen = buflen;
1998 
1999 	/* find tagged parameter */
2000 	while (totlen >= TLV_HDR_LEN) {
2001 		int len = elt->len;
2002 
2003 		do {
2004 			/* validate remaining totlen */
2005 			if (totlen <  (int)(len + TLV_HDR_LEN))
2006 				break;
2007 
2008 			if (id_ext) {
2009 				if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key))
2010 					break;
2011 			} else if (elt->id != key) {
2012 				break;
2013 			}
2014 
2015 			return (elt);
2016 		} while (0);
2017 
2018 		elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2019 		totlen -= (len + TLV_HDR_LEN);
2020 	}
2021 
2022 	return NULL;
2023 }
2024 
2025 /*
2026  * Traverse a string of 1-byte tag/1-byte length/variable-length value
2027  * triples, returning a pointer to the substring whose first element
2028  * matches tag
2029  * return NULL if not found or length field < min_varlen
2030  */
2031 bcm_tlv_t *
bcm_parse_tlvs_min_bodylen(void * buf,int buflen,uint key,int min_bodylen)2032 bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen)
2033 {
2034 	bcm_tlv_t * ret;
2035 	ret = bcm_parse_tlvs(buf, buflen, key);
2036 	if (ret == NULL || ret->len < min_bodylen) {
2037 		return NULL;
2038 	}
2039 	return ret;
2040 }
2041 
2042 /*
2043  * Traverse a string of 1-byte tag/1-byte length/variable-length value
2044  * triples, returning a pointer to the substring whose first element
2045  * matches tag.  Stop parsing when we see an element whose ID is greater
2046  * than the target key.
2047  */
2048 bcm_tlv_t *
bcm_parse_ordered_tlvs(void * buf,int buflen,uint key)2049 bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
2050 {
2051 	bcm_tlv_t *elt;
2052 	int totlen;
2053 
2054 	elt = (bcm_tlv_t*)buf;
2055 	totlen = buflen;
2056 
2057 	/* find tagged parameter */
2058 	while (totlen >= TLV_HDR_LEN) {
2059 		uint id = elt->id;
2060 		int len = elt->len;
2061 
2062 		/* Punt if we start seeing IDs > than target key */
2063 		if (id > key) {
2064 			return (NULL);
2065 		}
2066 
2067 		/* validate remaining totlen */
2068 		if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
2069 			return (elt);
2070 		}
2071 
2072 		elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2073 		totlen -= (len + TLV_HDR_LEN);
2074 	}
2075 	return NULL;
2076 }
2077 #endif	/* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
2078 
2079 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
2080 	defined(DHD_DEBUG)
2081 int
bcm_format_field(const bcm_bit_desc_ex_t * bd,uint32 flags,char * buf,int len)2082 bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len)
2083 {
2084 	int i, slen = 0;
2085 	uint32 bit, mask;
2086 	const char *name;
2087 	mask = bd->mask;
2088 	if (len < 2 || !buf)
2089 		return 0;
2090 
2091 	buf[0] = '\0';
2092 
2093 	for (i = 0;  (name = bd->bitfield[i].name) != NULL; i++) {
2094 		bit = bd->bitfield[i].bit;
2095 		if ((flags & mask) == bit) {
2096 			if (len > (int)strlen(name)) {
2097 				slen = strlen(name);
2098 				strncpy(buf, name, slen+1);
2099 			}
2100 			break;
2101 		}
2102 	}
2103 	return slen;
2104 }
2105 
2106 int
bcm_format_flags(const bcm_bit_desc_t * bd,uint32 flags,char * buf,int len)2107 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
2108 {
2109 	int i;
2110 	char* p = buf;
2111 	char hexstr[16];
2112 	int slen = 0, nlen = 0;
2113 	uint32 bit;
2114 	const char* name;
2115 
2116 	if (len < 2 || !buf)
2117 		return 0;
2118 
2119 	buf[0] = '\0';
2120 
2121 	for (i = 0; flags != 0; i++) {
2122 		bit = bd[i].bit;
2123 		name = bd[i].name;
2124 		if (bit == 0 && flags != 0) {
2125 			/* print any unnamed bits */
2126 			snprintf(hexstr, 16, "0x%X", flags);
2127 			name = hexstr;
2128 			flags = 0;	/* exit loop */
2129 		} else if ((flags & bit) == 0)
2130 			continue;
2131 		flags &= ~bit;
2132 		nlen = strlen(name);
2133 		slen += nlen;
2134 		/* count btwn flag space */
2135 		if (flags != 0)
2136 			slen += 1;
2137 		/* need NULL char as well */
2138 		if (len <= slen)
2139 			break;
2140 		/* copy NULL char but don't count it */
2141 		strncpy(p, name, nlen + 1);
2142 		p += nlen;
2143 		/* copy btwn flag space and NULL char */
2144 		if (flags != 0)
2145 			p += snprintf(p, 2, " ");
2146 	}
2147 
2148 	/* indicate the str was too short */
2149 	if (flags != 0) {
2150 		p += snprintf(p, 2, ">");
2151 	}
2152 
2153 	return (int)(p - buf);
2154 }
2155 #endif
2156 
2157 /* print bytes formatted as hex to a string. return the resulting string length */
2158 int
bcm_format_hex(char * str,const void * bytes,int len)2159 bcm_format_hex(char *str, const void *bytes, int len)
2160 {
2161 	int i;
2162 	char *p = str;
2163 	const uint8 *src = (const uint8*)bytes;
2164 
2165 	for (i = 0; i < len; i++) {
2166 		p += snprintf(p, 3, "%02X", *src);
2167 		src++;
2168 	}
2169 	return (int)(p - str);
2170 }
2171 
2172 /* pretty hex print a contiguous buffer */
2173 void
prhex(const char * msg,volatile uchar * buf,uint nbytes)2174 prhex(const char *msg, volatile uchar *buf, uint nbytes)
2175 {
2176 	char line[128], *p;
2177 	int len = sizeof(line);
2178 	int nchar;
2179 	uint i;
2180 
2181 	if (msg && (msg[0] != '\0'))
2182 		printf("%s:\n", msg);
2183 
2184 	p = line;
2185 	for (i = 0; i < nbytes; i++) {
2186 		if (i % 16 == 0) {
2187 			nchar = snprintf(p, len, "  %04x: ", i);	/* line prefix */
2188 			p += nchar;
2189 			len -= nchar;
2190 		}
2191 		if (len > 0) {
2192 			nchar = snprintf(p, len, "%02x ", buf[i]);
2193 			p += nchar;
2194 			len -= nchar;
2195 		}
2196 
2197 		if (i % 16 == 15) {
2198 			printf("%s\n", line);		/* flush line */
2199 			p = line;
2200 			len = sizeof(line);
2201 		}
2202 	}
2203 
2204 	/* flush last partial line */
2205 	if (p != line)
2206 		printf("%s\n", line);
2207 }
2208 
2209 static const char *crypto_algo_names[] = {
2210 	"NONE",
2211 	"WEP1",
2212 	"TKIP",
2213 	"WEP128",
2214 	"AES_CCM",
2215 	"AES_OCB_MSDU",
2216 	"AES_OCB_MPDU",
2217 	"NALG",
2218 	"UNDEF",
2219 	"UNDEF",
2220 	"UNDEF",
2221 	"UNDEF"
2222 	"PMK",
2223 	"BIP",
2224 	"AES_GCM",
2225 	"AES_CCM256",
2226 	"AES_GCM256",
2227 	"BIP_CMAC256",
2228 	"BIP_GMAC",
2229 	"BIP_GMAC256",
2230 	"UNDEF"
2231 };
2232 
2233 const char *
bcm_crypto_algo_name(uint algo)2234 bcm_crypto_algo_name(uint algo)
2235 {
2236 	return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
2237 }
2238 
2239 
2240 char *
bcm_chipname(uint chipid,char * buf,uint len)2241 bcm_chipname(uint chipid, char *buf, uint len)
2242 {
2243 	const char *fmt;
2244 
2245 	fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
2246 	snprintf(buf, len, fmt, chipid);
2247 	return buf;
2248 }
2249 
2250 /* Produce a human-readable string for boardrev */
2251 char *
bcm_brev_str(uint32 brev,char * buf)2252 bcm_brev_str(uint32 brev, char *buf)
2253 {
2254 	if (brev < 0x100)
2255 		snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
2256 	else
2257 		snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
2258 
2259 	return (buf);
2260 }
2261 
2262 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2263 
2264 /* dump large strings to console */
2265 void
printbig(char * buf)2266 printbig(char *buf)
2267 {
2268 	uint len, max_len;
2269 	char c;
2270 
2271 	len = (uint)strlen(buf);
2272 
2273 	max_len = BUFSIZE_TODUMP_ATONCE;
2274 
2275 	while (len > max_len) {
2276 		c = buf[max_len];
2277 		buf[max_len] = '\0';
2278 		printf("%s", buf);
2279 		buf[max_len] = c;
2280 
2281 		buf += max_len;
2282 		len -= max_len;
2283 	}
2284 	/* print the remaining string */
2285 	printf("%s\n", buf);
2286 	return;
2287 }
2288 
2289 /* routine to dump fields in a fileddesc structure */
2290 uint
bcmdumpfields(bcmutl_rdreg_rtn read_rtn,void * arg0,uint arg1,struct fielddesc * fielddesc_array,char * buf,uint32 bufsize)2291 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
2292 	char *buf, uint32 bufsize)
2293 {
2294 	uint  filled_len;
2295 	int len;
2296 	struct fielddesc *cur_ptr;
2297 
2298 	filled_len = 0;
2299 	cur_ptr = fielddesc_array;
2300 
2301 	while (bufsize > 1) {
2302 		if (cur_ptr->nameandfmt == NULL)
2303 			break;
2304 		len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
2305 		               read_rtn(arg0, arg1, cur_ptr->offset));
2306 		/* check for snprintf overflow or error */
2307 		if (len < 0 || (uint32)len >= bufsize)
2308 			len = bufsize - 1;
2309 		buf += len;
2310 		bufsize -= len;
2311 		filled_len += len;
2312 		cur_ptr++;
2313 	}
2314 	return filled_len;
2315 }
2316 
2317 uint
bcm_mkiovar(const char * name,const char * data,uint datalen,char * buf,uint buflen)2318 bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint buflen)
2319 {
2320 	uint len;
2321 
2322 	len = (uint)strlen(name) + 1;
2323 
2324 	if ((len + datalen) > buflen)
2325 		return 0;
2326 
2327 	strncpy(buf, name, buflen);
2328 
2329 	/* append data onto the end of the name string */
2330 	if (data && datalen != 0) {
2331 		memcpy(&buf[len], data, datalen);
2332 		len += datalen;
2333 	}
2334 
2335 	return len;
2336 }
2337 
2338 /* Quarter dBm units to mW
2339  * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
2340  * Table is offset so the last entry is largest mW value that fits in
2341  * a uint16.
2342  */
2343 
2344 #define QDBM_OFFSET 153		/* Offset for first entry */
2345 #define QDBM_TABLE_LEN 40	/* Table size */
2346 
2347 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
2348  * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
2349  */
2350 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
2351 
2352 /* Largest mW value that will round down to the last table entry,
2353  * QDBM_OFFSET + QDBM_TABLE_LEN-1.
2354  * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
2355  */
2356 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
2357 
2358 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
2359 /* qdBm: 	+0 	+1 	+2 	+3 	+4 	+5 	+6 	+7 */
2360 /* 153: */      6683,	7079,	7499,	7943,	8414,	8913,	9441,	10000,
2361 /* 161: */      10593,	11220,	11885,	12589,	13335,	14125,	14962,	15849,
2362 /* 169: */      16788,	17783,	18836,	19953,	21135,	22387,	23714,	25119,
2363 /* 177: */      26607,	28184,	29854,	31623,	33497,	35481,	37584,	39811,
2364 /* 185: */      42170,	44668,	47315,	50119,	53088,	56234,	59566,	63096
2365 };
2366 
2367 uint16
bcm_qdbm_to_mw(uint8 qdbm)2368 bcm_qdbm_to_mw(uint8 qdbm)
2369 {
2370 	uint factor = 1;
2371 	int idx = qdbm - QDBM_OFFSET;
2372 
2373 	if (idx >= QDBM_TABLE_LEN) {
2374 		/* clamp to max uint16 mW value */
2375 		return 0xFFFF;
2376 	}
2377 
2378 	/* scale the qdBm index up to the range of the table 0-40
2379 	 * where an offset of 40 qdBm equals a factor of 10 mW.
2380 	 */
2381 	while (idx < 0) {
2382 		idx += 40;
2383 		factor *= 10;
2384 	}
2385 
2386 	/* return the mW value scaled down to the correct factor of 10,
2387 	 * adding in factor/2 to get proper rounding.
2388 	 */
2389 	return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
2390 }
2391 
2392 uint8
bcm_mw_to_qdbm(uint16 mw)2393 bcm_mw_to_qdbm(uint16 mw)
2394 {
2395 	uint8 qdbm;
2396 	int offset;
2397 	uint mw_uint = mw;
2398 	uint boundary;
2399 
2400 	/* handle boundary case */
2401 	if (mw_uint <= 1)
2402 		return 0;
2403 
2404 	offset = QDBM_OFFSET;
2405 
2406 	/* move mw into the range of the table */
2407 	while (mw_uint < QDBM_TABLE_LOW_BOUND) {
2408 		mw_uint *= 10;
2409 		offset -= 40;
2410 	}
2411 
2412 	for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
2413 		boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
2414 		                                    nqdBm_to_mW_map[qdbm])/2;
2415 		if (mw_uint < boundary) break;
2416 	}
2417 
2418 	qdbm += (uint8)offset;
2419 
2420 	return (qdbm);
2421 }
2422 
2423 
2424 uint
bcm_bitcount(uint8 * bitmap,uint length)2425 bcm_bitcount(uint8 *bitmap, uint length)
2426 {
2427 	uint bitcount = 0, i;
2428 	uint8 tmp;
2429 	for (i = 0; i < length; i++) {
2430 		tmp = bitmap[i];
2431 		while (tmp) {
2432 			bitcount++;
2433 			tmp &= (tmp - 1);
2434 		}
2435 	}
2436 	return bitcount;
2437 }
2438 
2439 #if defined(BCMDRIVER) || defined(WL_UNITTEST)
2440 
2441 /* triggers bcm_bprintf to print to kernel log */
2442 bool bcm_bprintf_bypass = FALSE;
2443 
2444 /* Initialization of bcmstrbuf structure */
2445 void
bcm_binit(struct bcmstrbuf * b,char * buf,uint size)2446 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
2447 {
2448 	b->origsize = b->size = size;
2449 	b->origbuf = b->buf = buf;
2450 }
2451 
2452 /* Buffer sprintf wrapper to guard against buffer overflow */
2453 int
bcm_bprintf(struct bcmstrbuf * b,const char * fmt,...)2454 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
2455 {
2456 	va_list ap;
2457 	int r;
2458 
2459 	va_start(ap, fmt);
2460 
2461 	r = vsnprintf(b->buf, b->size, fmt, ap);
2462 	if (bcm_bprintf_bypass == TRUE) {
2463 		printf("%s", b->buf);
2464 		goto exit;
2465 	}
2466 
2467 	/* Non Ansi C99 compliant returns -1,
2468 	 * Ansi compliant return r >= b->size,
2469 	 * bcmstdlib returns 0, handle all
2470 	 */
2471 	/* r == 0 is also the case when strlen(fmt) is zero.
2472 	 * typically the case when "" is passed as argument.
2473 	 */
2474 	if ((r == -1) || (r >= (int)b->size)) {
2475 		b->size = 0;
2476 	} else {
2477 		b->size -= r;
2478 		b->buf += r;
2479 	}
2480 
2481 exit:
2482 	va_end(ap);
2483 
2484 	return r;
2485 }
2486 
2487 void
bcm_bprhex(struct bcmstrbuf * b,const char * msg,bool newline,const uint8 * buf,int len)2488 bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len)
2489 {
2490 	int i;
2491 
2492 	if (msg != NULL && msg[0] != '\0')
2493 		bcm_bprintf(b, "%s", msg);
2494 	for (i = 0; i < len; i ++)
2495 		bcm_bprintf(b, "%02X", buf[i]);
2496 	if (newline)
2497 		bcm_bprintf(b, "\n");
2498 }
2499 
2500 void
bcm_inc_bytes(uchar * num,int num_bytes,uint8 amount)2501 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
2502 {
2503 	int i;
2504 
2505 	for (i = 0; i < num_bytes; i++) {
2506 		num[i] += amount;
2507 		if (num[i] >= amount)
2508 			break;
2509 		amount = 1;
2510 	}
2511 }
2512 
2513 int
bcm_cmp_bytes(const uchar * arg1,const uchar * arg2,uint8 nbytes)2514 bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
2515 {
2516 	int i;
2517 
2518 	for (i = nbytes - 1; i >= 0; i--) {
2519 		if (arg1[i] != arg2[i])
2520 			return (arg1[i] - arg2[i]);
2521 	}
2522 	return 0;
2523 }
2524 
2525 void
bcm_print_bytes(const char * name,const uchar * data,int len)2526 bcm_print_bytes(const char *name, const uchar *data, int len)
2527 {
2528 	int i;
2529 	int per_line = 0;
2530 
2531 	printf("%s: %d \n", name ? name : "", len);
2532 	for (i = 0; i < len; i++) {
2533 		printf("%02x ", *data++);
2534 		per_line++;
2535 		if (per_line == 16) {
2536 			per_line = 0;
2537 			printf("\n");
2538 		}
2539 	}
2540 	printf("\n");
2541 }
2542 
2543 /* Look for vendor-specific IE with specified OUI and optional type */
2544 bcm_tlv_t *
bcm_find_vendor_ie(void * tlvs,int tlvs_len,const char * voui,uint8 * type,int type_len)2545 bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len)
2546 {
2547 	bcm_tlv_t *ie;
2548 	uint8 ie_len;
2549 
2550 	ie = (bcm_tlv_t*)tlvs;
2551 
2552 	/* make sure we are looking at a valid IE */
2553 	if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
2554 		return NULL;
2555 	}
2556 
2557 	/* Walk through the IEs looking for an OUI match */
2558 	do {
2559 		ie_len = ie->len;
2560 		if ((ie->id == DOT11_MNG_PROPR_ID) &&
2561 		    (ie_len >= (DOT11_OUI_LEN + type_len)) &&
2562 		    !bcmp(ie->data, voui, DOT11_OUI_LEN))
2563 		{
2564 			/* compare optional type */
2565 			if (type_len == 0 ||
2566 			    !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
2567 				return (ie);		/* a match */
2568 			}
2569 		}
2570 	} while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
2571 
2572 	return NULL;
2573 }
2574 
2575 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
2576 	defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
2577 #define SSID_FMT_BUF_LEN	((4 * DOT11_MAX_SSID_LEN) + 1)
2578 
2579 int
bcm_format_ssid(char * buf,const uchar ssid[],uint ssid_len)2580 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
2581 {
2582 	uint i, c;
2583 	char *p = buf;
2584 	char *endp = buf + SSID_FMT_BUF_LEN;
2585 
2586 	if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
2587 
2588 	for (i = 0; i < ssid_len; i++) {
2589 		c = (uint)ssid[i];
2590 		if (c == '\\') {
2591 			*p++ = '\\';
2592 			*p++ = '\\';
2593 		} else if (bcm_isprint((uchar)c)) {
2594 			*p++ = (char)c;
2595 		} else {
2596 			p += snprintf(p, (endp - p), "\\x%02X", c);
2597 		}
2598 	}
2599 	*p = '\0';
2600 	ASSERT(p < endp);
2601 
2602 	return (int)(p - buf);
2603 }
2604 #endif
2605 
2606 #endif /* BCMDRIVER || WL_UNITTEST */
2607 
2608 /*
2609  * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
2610  * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
2611  * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
2612  * Shortens buffer as needed and pads with NULs.  End of buffer is marked by two NULs.
2613 */
2614 
2615 unsigned int
process_nvram_vars(char * varbuf,unsigned int len)2616 process_nvram_vars(char *varbuf, unsigned int len)
2617 {
2618 	char *dp;
2619 	bool findNewline;
2620 	int column;
2621 	unsigned int buf_len, n;
2622 	unsigned int pad = 0;
2623 	char nv_ver[128];
2624 
2625 	dp = varbuf;
2626 
2627 	findNewline = FALSE;
2628 	column = 0;
2629 
2630 	// terence 20130914: print out NVRAM version
2631 	if (varbuf[0] == '#') {
2632 		memset(nv_ver, 0x00, sizeof(nv_ver));
2633 		for (n=1; n<len && n<(sizeof(nv_ver)-1); n++) {
2634 			if (varbuf[n] == '\n')
2635 				break;
2636 			nv_ver[n-1] = varbuf[n];
2637 		}
2638 		printf("NVRAM version: %s\n", nv_ver);
2639 	}
2640 
2641 	for (n = 0; n < len; n++) {
2642 		if (varbuf[n] == '\r')
2643 			continue;
2644 		if (findNewline && varbuf[n] != '\n')
2645 			continue;
2646 		findNewline = FALSE;
2647 		if (varbuf[n] == '#') {
2648 			findNewline = TRUE;
2649 			continue;
2650 		}
2651 		if (varbuf[n] == '\n') {
2652 			if (column == 0)
2653 				continue;
2654 			*dp++ = 0;
2655 			column = 0;
2656 			continue;
2657 		}
2658 		*dp++ = varbuf[n];
2659 		column++;
2660 	}
2661 	buf_len = (unsigned int)(dp - varbuf);
2662 	if (buf_len % 4) {
2663 		pad = 4 - buf_len % 4;
2664 		if (pad && (buf_len + pad <= len)) {
2665 			buf_len += pad;
2666 		}
2667 	}
2668 
2669 	while (dp < varbuf + n)
2670 		*dp++ = 0;
2671 
2672 	return buf_len;
2673 }
2674 
2675 /* calculate a * b + c */
2676 void
bcm_uint64_multiple_add(uint32 * r_high,uint32 * r_low,uint32 a,uint32 b,uint32 c)2677 bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
2678 {
2679 #define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
2680 	uint32 r1, r0;
2681 	uint32 a1, a0, b1, b0, t, cc = 0;
2682 
2683 	a1 = a >> 16;
2684 	a0 = a & 0xffff;
2685 	b1 = b >> 16;
2686 	b0 = b & 0xffff;
2687 
2688 	r0 = a0 * b0;
2689 	FORMALIZE(r0);
2690 
2691 	t = (a1 * b0) << 16;
2692 	FORMALIZE(t);
2693 
2694 	r0 += t;
2695 	FORMALIZE(r0);
2696 
2697 	t = (a0 * b1) << 16;
2698 	FORMALIZE(t);
2699 
2700 	r0 += t;
2701 	FORMALIZE(r0);
2702 
2703 	FORMALIZE(c);
2704 
2705 	r0 += c;
2706 	FORMALIZE(r0);
2707 
2708 	r0 |= (cc % 2) ? 0x80000000 : 0;
2709 	r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2);
2710 
2711 	*r_high = r1;
2712 	*r_low = r0;
2713 }
2714 
2715 /* calculate a / b */
2716 void
bcm_uint64_divide(uint32 * r,uint32 a_high,uint32 a_low,uint32 b)2717 bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
2718 {
2719 	uint32 a1 = a_high, a0 = a_low, r0 = 0;
2720 
2721 	if (b < 2)
2722 		return;
2723 
2724 	while (a1 != 0) {
2725 		r0 += (0xffffffff / b) * a1;
2726 		bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
2727 	}
2728 
2729 	r0 += a0 / b;
2730 	*r = r0;
2731 }
2732 
2733 #ifndef setbit /* As in the header file */
2734 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
2735 /* Set bit in byte array. */
2736 void
setbit(void * array,uint bit)2737 setbit(void *array, uint bit)
2738 {
2739 	((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
2740 }
2741 
2742 /* Clear bit in byte array. */
2743 void
clrbit(void * array,uint bit)2744 clrbit(void *array, uint bit)
2745 {
2746 	((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
2747 }
2748 
2749 /* Test if bit is set in byte array. */
2750 bool
isset(const void * array,uint bit)2751 isset(const void *array, uint bit)
2752 {
2753 	return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY)));
2754 }
2755 
2756 /* Test if bit is clear in byte array. */
2757 bool
isclr(const void * array,uint bit)2758 isclr(const void *array, uint bit)
2759 {
2760 	return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0);
2761 }
2762 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
2763 #endif /* setbit */
2764 
2765 void
set_bitrange(void * array,uint start,uint end,uint maxbit)2766 set_bitrange(void *array, uint start, uint end, uint maxbit)
2767 {
2768 	uint startbyte = start/NBBY;
2769 	uint endbyte = end/NBBY;
2770 	uint i, startbytelastbit, endbytestartbit;
2771 
2772 	if (end >= start) {
2773 		if (endbyte - startbyte > 1)
2774 		{
2775 			startbytelastbit = (startbyte+1)*NBBY - 1;
2776 			endbytestartbit = endbyte*NBBY;
2777 			for (i = startbyte+1; i < endbyte; i++)
2778 				((uint8 *)array)[i] = 0xFF;
2779 			for (i = start; i <= startbytelastbit; i++)
2780 				setbit(array, i);
2781 			for (i = endbytestartbit; i <= end; i++)
2782 				setbit(array, i);
2783 		} else {
2784 			for (i = start; i <= end; i++)
2785 				setbit(array, i);
2786 		}
2787 	}
2788 	else {
2789 		set_bitrange(array, start, maxbit, maxbit);
2790 		set_bitrange(array, 0, end, maxbit);
2791 	}
2792 }
2793 
2794 void
bcm_bitprint32(const uint32 u32arg)2795 bcm_bitprint32(const uint32 u32arg)
2796 {
2797 	int i;
2798 	for (i = NBITS(uint32) - 1; i >= 0; i--) {
2799 		if (isbitset(u32arg, i)) {
2800 			printf("1");
2801 		} else {
2802 			printf("0");
2803 		}
2804 
2805 		if ((i % NBBY) == 0) printf(" ");
2806 	}
2807 	printf("\n");
2808 }
2809 
2810 /* calculate checksum for ip header, tcp / udp header / data */
2811 uint16
bcm_ip_cksum(uint8 * buf,uint32 len,uint32 sum)2812 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
2813 {
2814 	while (len > 1) {
2815 		sum += (buf[0] << 8) | buf[1];
2816 		buf += 2;
2817 		len -= 2;
2818 	}
2819 
2820 	if (len > 0) {
2821 		sum += (*buf) << 8;
2822 	}
2823 
2824 	while (sum >> 16) {
2825 		sum = (sum & 0xffff) + (sum >> 16);
2826 	}
2827 
2828 	return ((uint16)~sum);
2829 }
2830 #if defined(BCMDRIVER) && !defined(_CFEZ_)
2831 /*
2832  * Hierarchical Multiword bitmap based small id allocator.
2833  *
2834  * Multilevel hierarchy bitmap. (maximum 2 levels)
2835  * First hierarchy uses a multiword bitmap to identify 32bit words in the
2836  * second hierarchy that have at least a single bit set. Each bit in a word of
2837  * the second hierarchy represents a unique ID that may be allocated.
2838  *
2839  * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
2840  * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
2841  * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
2842  * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
2843  *                       non-zero bitmap word carrying at least one free ID.
2844  * BCM_MWBMAP_SHIFT_OP:  Used in MOD, DIV and MUL operations.
2845  * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
2846  *
2847  * Design Notes:
2848  * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
2849  * bits are computed each time on allocation and deallocation, requiring 4
2850  * array indexed access and 3 arithmetic operations. When not defined, a runtime
2851  * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
2852  * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
2853  * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
2854  * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
2855  *
2856  * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
2857  * size is fixed. No intention to support larger than 4K indice allocation. ID
2858  * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
2859  * with savings in not having to use an indirect access, had it been dynamically
2860  * allocated.
2861  */
2862 #define BCM_MWBMAP_ITEMS_MAX    (64 * 1024)  /* May increase to 64K */
2863 
2864 #define BCM_MWBMAP_BITS_WORD    (NBITS(uint32))
2865 #define BCM_MWBMAP_WORDS_MAX    (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
2866 #define BCM_MWBMAP_WDMAP_MAX    (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
2867 #define BCM_MWBMAP_SHIFT_OP     (5)
2868 #define BCM_MWBMAP_MODOP(ix)    ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
2869 #define BCM_MWBMAP_DIVOP(ix)    ((ix) >> BCM_MWBMAP_SHIFT_OP)
2870 #define BCM_MWBMAP_MULOP(ix)    ((ix) << BCM_MWBMAP_SHIFT_OP)
2871 
2872 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
2873 #define BCM_MWBMAP_PTR(hdl)		((struct bcm_mwbmap *)(hdl))
2874 #define BCM_MWBMAP_HDL(ptr)		((void *)(ptr))
2875 
2876 #if defined(BCM_MWBMAP_DEBUG)
2877 #define BCM_MWBMAP_AUDIT(mwb) \
2878 	do { \
2879 		ASSERT((mwb != NULL) && \
2880 		       (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
2881 		bcm_mwbmap_audit(mwb); \
2882 	} while (0)
2883 #define MWBMAP_ASSERT(exp)		ASSERT(exp)
2884 #define MWBMAP_DBG(x)           printf x
2885 #else   /* !BCM_MWBMAP_DEBUG */
2886 #define BCM_MWBMAP_AUDIT(mwb)   do {} while (0)
2887 #define MWBMAP_ASSERT(exp)		do {} while (0)
2888 #define MWBMAP_DBG(x)
2889 #endif  /* !BCM_MWBMAP_DEBUG */
2890 
2891 
2892 typedef struct bcm_mwbmap {     /* Hierarchical multiword bitmap allocator    */
2893 	uint16 wmaps;               /* Total number of words in free wd bitmap    */
2894 	uint16 imaps;               /* Total number of words in free id bitmap    */
2895 	int32  ifree;               /* Count of free indices. Used only in audits */
2896 	uint16 total;               /* Total indices managed by multiword bitmap  */
2897 
2898 	void * magic;               /* Audit handle parameter from user           */
2899 
2900 	uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of            */
2901 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2902 	int8   wd_count[BCM_MWBMAP_WORDS_MAX];  /* free id running count, 1st lvl */
2903 #endif /*  ! BCM_MWBMAP_USE_CNTSETBITS */
2904 
2905 	uint32 id_bitmap[0];        /* Second level bitmap                        */
2906 } bcm_mwbmap_t;
2907 
2908 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
2909 struct bcm_mwbmap *
bcm_mwbmap_init(osl_t * osh,uint32 items_max)2910 bcm_mwbmap_init(osl_t *osh, uint32 items_max)
2911 {
2912 	struct bcm_mwbmap * mwbmap_p;
2913 	uint32 wordix, size, words, extra;
2914 
2915 	/* Implementation Constraint: Uses 32bit word bitmap */
2916 	MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
2917 	MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
2918 	MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
2919 	MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
2920 
2921 	ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
2922 
2923 	/* Determine the number of words needed in the multiword bitmap */
2924 	extra = BCM_MWBMAP_MODOP(items_max);
2925 	words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
2926 
2927 	/* Allocate runtime state of multiword bitmap */
2928 	/* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
2929 	size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
2930 	mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
2931 	if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
2932 		ASSERT(0);
2933 		goto error1;
2934 	}
2935 	memset(mwbmap_p, 0, size);
2936 
2937 	/* Initialize runtime multiword bitmap state */
2938 	mwbmap_p->imaps = (uint16)words;
2939 	mwbmap_p->ifree = (int32)items_max;
2940 	mwbmap_p->total = (uint16)items_max;
2941 
2942 	/* Setup magic, for use in audit of handle */
2943 	mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
2944 
2945 	/* Setup the second level bitmap of free indices */
2946 	/* Mark all indices as available */
2947 	for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
2948 		mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
2949 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2950 		mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
2951 #endif /*  ! BCM_MWBMAP_USE_CNTSETBITS */
2952 	}
2953 
2954 	/* Ensure that extra indices are tagged as un-available */
2955 	if (extra) { /* fixup the free ids in last bitmap and wd_count */
2956 		uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
2957 		*bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2958 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2959 		mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
2960 #endif /*  ! BCM_MWBMAP_USE_CNTSETBITS */
2961 	}
2962 
2963 	/* Setup the first level bitmap hierarchy */
2964 	extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
2965 	words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
2966 
2967 	mwbmap_p->wmaps = (uint16)words;
2968 
2969 	for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
2970 		mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
2971 	if (extra) {
2972 		uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
2973 		*bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2974 	}
2975 
2976 	return mwbmap_p;
2977 
2978 error1:
2979 	return BCM_MWBMAP_INVALID_HDL;
2980 }
2981 
2982 /* Release resources used by multiword bitmap based small index allocator. */
2983 void
bcm_mwbmap_fini(osl_t * osh,struct bcm_mwbmap * mwbmap_hdl)2984 bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
2985 {
2986 	bcm_mwbmap_t * mwbmap_p;
2987 
2988 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
2989 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2990 
2991 	MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
2992 	                     + (sizeof(uint32) * mwbmap_p->imaps));
2993 	return;
2994 }
2995 
2996 /* Allocate a unique small index using a multiword bitmap index allocator.    */
2997 uint32 BCMFASTPATH
bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)2998 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
2999 {
3000 	bcm_mwbmap_t * mwbmap_p;
3001 	uint32 wordix, bitmap;
3002 
3003 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
3004 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3005 
3006 	/* Start with the first hierarchy */
3007 	for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
3008 
3009 		bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
3010 
3011 		if (bitmap != 0U) {
3012 
3013 			uint32 count, bitix, *bitmap_p;
3014 
3015 			bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3016 
3017 			/* clear all except trailing 1 */
3018 			bitmap   = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
3019 			MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
3020 			              bcm_count_leading_zeros(bitmap));
3021 			bitix    = (BCM_MWBMAP_BITS_WORD - 1)
3022 			         - bcm_count_leading_zeros(bitmap); /* use asm clz */
3023 			wordix   = BCM_MWBMAP_MULOP(wordix) + bitix;
3024 
3025 			/* Clear bit if wd count is 0, without conditional branch */
3026 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3027 			count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
3028 #else  /* ! BCM_MWBMAP_USE_CNTSETBITS */
3029 			mwbmap_p->wd_count[wordix]--;
3030 			count = mwbmap_p->wd_count[wordix];
3031 			MWBMAP_ASSERT(count ==
3032 			              (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
3033 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3034 			MWBMAP_ASSERT(count >= 0);
3035 
3036 			/* clear wd_bitmap bit if id_map count is 0 */
3037 			bitmap = (count == 0) << bitix;
3038 
3039 			MWBMAP_DBG((
3040 			    "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
3041 			    bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
3042 
3043 			*bitmap_p ^= bitmap;
3044 
3045 			/* Use bitix in the second hierarchy */
3046 			bitmap_p = &mwbmap_p->id_bitmap[wordix];
3047 
3048 			bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
3049 			MWBMAP_ASSERT(bitmap != 0U);
3050 
3051 			/* clear all except trailing 1 */
3052 			bitmap   = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
3053 			MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
3054 			              bcm_count_leading_zeros(bitmap));
3055 			bitix    = BCM_MWBMAP_MULOP(wordix)
3056 			         + (BCM_MWBMAP_BITS_WORD - 1)
3057 			         - bcm_count_leading_zeros(bitmap); /* use asm clz */
3058 
3059 			mwbmap_p->ifree--; /* decrement system wide free count */
3060 			MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
3061 
3062 			MWBMAP_DBG((
3063 			    "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
3064 			    bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
3065 			    mwbmap_p->ifree));
3066 
3067 			*bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
3068 
3069 			return bitix;
3070 		}
3071 	}
3072 
3073 	ASSERT(mwbmap_p->ifree == 0);
3074 
3075 	return BCM_MWBMAP_INVALID_IDX;
3076 }
3077 
3078 /* Force an index at a specified position to be in use */
3079 void
bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)3080 bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
3081 {
3082 	bcm_mwbmap_t * mwbmap_p;
3083 	uint32 count, wordix, bitmap, *bitmap_p;
3084 
3085 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
3086 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3087 
3088 	ASSERT(bitix < mwbmap_p->total);
3089 
3090 	/* Start with second hierarchy */
3091 	wordix   = BCM_MWBMAP_DIVOP(bitix);
3092 	bitmap   = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
3093 	bitmap_p = &mwbmap_p->id_bitmap[wordix];
3094 
3095 	ASSERT((*bitmap_p & bitmap) == bitmap);
3096 
3097 	mwbmap_p->ifree--; /* update free count */
3098 	ASSERT(mwbmap_p->ifree >= 0);
3099 
3100 	MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
3101 	           bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
3102 	           mwbmap_p->ifree));
3103 
3104 	*bitmap_p ^= bitmap; /* mark as in use */
3105 
3106 	/* Update first hierarchy */
3107 	bitix    = wordix;
3108 
3109 	wordix   = BCM_MWBMAP_DIVOP(bitix);
3110 	bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3111 
3112 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3113 	count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
3114 #else  /* ! BCM_MWBMAP_USE_CNTSETBITS */
3115 	mwbmap_p->wd_count[bitix]--;
3116 	count = mwbmap_p->wd_count[bitix];
3117 	MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
3118 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3119 	MWBMAP_ASSERT(count >= 0);
3120 
3121 	bitmap   = (count == 0) << BCM_MWBMAP_MODOP(bitix);
3122 
3123 	MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
3124 	           BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
3125 	           (*bitmap_p) ^ bitmap, count));
3126 
3127 	*bitmap_p ^= bitmap; /* mark as in use */
3128 
3129 	return;
3130 }
3131 
3132 /* Free a previously allocated index back into the multiword bitmap allocator */
3133 void BCMFASTPATH
bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)3134 bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
3135 {
3136 	bcm_mwbmap_t * mwbmap_p;
3137 	uint32 wordix, bitmap, *bitmap_p;
3138 
3139 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
3140 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3141 
3142 	ASSERT(bitix < mwbmap_p->total);
3143 
3144 	/* Start with second level hierarchy */
3145 	wordix   = BCM_MWBMAP_DIVOP(bitix);
3146 	bitmap   = (1U << BCM_MWBMAP_MODOP(bitix));
3147 	bitmap_p = &mwbmap_p->id_bitmap[wordix];
3148 
3149 	ASSERT((*bitmap_p & bitmap) == 0U);	/* ASSERT not a double free */
3150 
3151 	mwbmap_p->ifree++; /* update free count */
3152 	ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
3153 
3154 	MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
3155 	           bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
3156 	           mwbmap_p->ifree));
3157 
3158 	*bitmap_p |= bitmap; /* mark as available */
3159 
3160 	/* Now update first level hierarchy */
3161 
3162 	bitix    = wordix;
3163 
3164 	wordix   = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
3165 	bitmap   = (1U << BCM_MWBMAP_MODOP(bitix));
3166 	bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3167 
3168 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
3169 	mwbmap_p->wd_count[bitix]++;
3170 #endif
3171 
3172 #if defined(BCM_MWBMAP_DEBUG)
3173 	{
3174 		uint32 count;
3175 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3176 		count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
3177 #else  /*  ! BCM_MWBMAP_USE_CNTSETBITS */
3178 		count = mwbmap_p->wd_count[bitix];
3179 		MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
3180 #endif /*  ! BCM_MWBMAP_USE_CNTSETBITS */
3181 
3182 		MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
3183 
3184 		MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
3185 		            bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
3186 	}
3187 #endif /* BCM_MWBMAP_DEBUG */
3188 
3189 	*bitmap_p |= bitmap;
3190 
3191 	return;
3192 }
3193 
3194 /* Fetch the toal number of free indices in the multiword bitmap allocator */
3195 uint32
bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)3196 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
3197 {
3198 	bcm_mwbmap_t * mwbmap_p;
3199 
3200 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
3201 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3202 
3203 	ASSERT(mwbmap_p->ifree >= 0);
3204 
3205 	return mwbmap_p->ifree;
3206 }
3207 
3208 /* Determine whether an index is inuse or free */
3209 bool
bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)3210 bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
3211 {
3212 	bcm_mwbmap_t * mwbmap_p;
3213 	uint32 wordix, bitmap;
3214 
3215 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
3216 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3217 
3218 	ASSERT(bitix < mwbmap_p->total);
3219 
3220 	wordix   = BCM_MWBMAP_DIVOP(bitix);
3221 	bitmap   = (1U << BCM_MWBMAP_MODOP(bitix));
3222 
3223 	return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
3224 }
3225 
3226 /* Debug dump a multiword bitmap allocator */
3227 void
bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)3228 bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
3229 {
3230 	uint32 ix, count;
3231 	bcm_mwbmap_t * mwbmap_p;
3232 
3233 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
3234 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3235 
3236 	printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p,
3237 	       mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
3238 	for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
3239 		printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
3240 		bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
3241 		printf("\n");
3242 	}
3243 	for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
3244 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3245 		count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
3246 #else  /* ! BCM_MWBMAP_USE_CNTSETBITS */
3247 		count = mwbmap_p->wd_count[ix];
3248 		MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
3249 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3250 		printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
3251 		bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
3252 		printf("\n");
3253 	}
3254 
3255 	return;
3256 }
3257 
3258 /* Audit a hierarchical multiword bitmap */
3259 void
bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)3260 bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
3261 {
3262 	bcm_mwbmap_t * mwbmap_p;
3263 	uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
3264 
3265 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3266 
3267 	for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
3268 
3269 		bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3270 
3271 		for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
3272 			if ((*bitmap_p) & (1 << bitix)) {
3273 				idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
3274 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3275 				count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
3276 #else  /* ! BCM_MWBMAP_USE_CNTSETBITS */
3277 				count = mwbmap_p->wd_count[idmap_ix];
3278 				ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
3279 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3280 				ASSERT(count != 0U);
3281 				free_cnt += count;
3282 			}
3283 		}
3284 	}
3285 
3286 	ASSERT((int)free_cnt == mwbmap_p->ifree);
3287 }
3288 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
3289 
3290 /* Simple 16bit Id allocator using a stack implementation. */
3291 typedef struct id16_map {
3292 	uint32  failures;  /* count of failures */
3293 	void    *dbg;      /* debug placeholder */
3294 	uint16  total;     /* total number of ids managed by allocator */
3295 	uint16  start;     /* start value of 16bit ids to be managed */
3296 	int     stack_idx; /* index into stack of available ids */
3297 	uint16  stack[0];  /* stack of 16 bit ids */
3298 } id16_map_t;
3299 
3300 #define ID16_MAP_SZ(items)      (sizeof(id16_map_t) + \
3301 	                             (sizeof(uint16) * (items)))
3302 
3303 #if defined(BCM_DBG)
3304 
3305 /* Uncomment BCM_DBG_ID16 to debug double free */
3306 /* #define BCM_DBG_ID16 */
3307 
3308 typedef struct id16_map_dbg {
3309 	uint16  total;
3310 	bool    avail[0];
3311 } id16_map_dbg_t;
3312 #define ID16_MAP_DBG_SZ(items)  (sizeof(id16_map_dbg_t) + \
3313 	                             (sizeof(bool) * (items)))
3314 #define ID16_MAP_MSG(x)         print x
3315 #else
3316 #define ID16_MAP_MSG(x)
3317 #endif /* BCM_DBG */
3318 
3319 void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
id16_map_init(osl_t * osh,uint16 total_ids,uint16 start_val16)3320 id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
3321 {
3322 	uint16 idx, val16;
3323 	id16_map_t * id16_map;
3324 
3325 	ASSERT(total_ids > 0);
3326 
3327 	/* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
3328 	 * with random values.
3329 	 */
3330 	ASSERT((start_val16 == ID16_UNDEFINED) ||
3331 	       (start_val16 + total_ids) < ID16_INVALID);
3332 
3333 	id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
3334 	if (id16_map == NULL) {
3335 		return NULL;
3336 	}
3337 
3338 	id16_map->total = total_ids;
3339 	id16_map->start = start_val16;
3340 	id16_map->failures = 0;
3341 	id16_map->dbg = NULL;
3342 
3343 	/*
3344 	 * Populate stack with 16bit id values, commencing with start_val16.
3345 	 * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
3346 	 */
3347 	id16_map->stack_idx = -1;
3348 
3349 	if (id16_map->start != ID16_UNDEFINED) {
3350 		val16 = start_val16;
3351 
3352 		for (idx = 0; idx < total_ids; idx++, val16++) {
3353 			id16_map->stack_idx = idx;
3354 			id16_map->stack[id16_map->stack_idx] = val16;
3355 		}
3356 	}
3357 
3358 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3359 	if (id16_map->start != ID16_UNDEFINED) {
3360 		id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
3361 
3362 		if (id16_map->dbg) {
3363 			id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3364 
3365 			id16_map_dbg->total = total_ids;
3366 			for (idx = 0; idx < total_ids; idx++) {
3367 				id16_map_dbg->avail[idx] = TRUE;
3368 			}
3369 		}
3370 	}
3371 #endif /* BCM_DBG && BCM_DBG_ID16 */
3372 
3373 	return (void *)id16_map;
3374 }
3375 
3376 void * /* Destruct an id16 allocator instance */
id16_map_fini(osl_t * osh,void * id16_map_hndl)3377 id16_map_fini(osl_t *osh, void * id16_map_hndl)
3378 {
3379 	uint16 total_ids;
3380 	id16_map_t * id16_map;
3381 
3382 	if (id16_map_hndl == NULL)
3383 		return NULL;
3384 
3385 	id16_map = (id16_map_t *)id16_map_hndl;
3386 
3387 	total_ids = id16_map->total;
3388 	ASSERT(total_ids > 0);
3389 
3390 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3391 	if (id16_map->dbg) {
3392 		MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
3393 		id16_map->dbg = NULL;
3394 	}
3395 #endif /* BCM_DBG && BCM_DBG_ID16 */
3396 
3397 	id16_map->total = 0;
3398 	MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
3399 
3400 	return NULL;
3401 }
3402 
3403 void
id16_map_clear(void * id16_map_hndl,uint16 total_ids,uint16 start_val16)3404 id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
3405 {
3406 	uint16 idx, val16;
3407 	id16_map_t * id16_map;
3408 
3409 	ASSERT(total_ids > 0);
3410 	/* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
3411 	 * with random values.
3412 	 */
3413 	ASSERT((start_val16 == ID16_UNDEFINED) ||
3414 	       (start_val16 + total_ids) < ID16_INVALID);
3415 
3416 	id16_map = (id16_map_t *)id16_map_hndl;
3417 	if (id16_map == NULL) {
3418 		return;
3419 	}
3420 
3421 	id16_map->total = total_ids;
3422 	id16_map->start = start_val16;
3423 	id16_map->failures = 0;
3424 
3425 	/* Populate stack with 16bit id values, commencing with start_val16 */
3426 	id16_map->stack_idx = -1;
3427 
3428 	if (id16_map->start != ID16_UNDEFINED) {
3429 		val16 = start_val16;
3430 
3431 		for (idx = 0; idx < total_ids; idx++, val16++) {
3432 			id16_map->stack_idx = idx;
3433 			id16_map->stack[id16_map->stack_idx] = val16;
3434 		}
3435 	}
3436 
3437 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3438 	if (id16_map->start != ID16_UNDEFINED) {
3439 		if (id16_map->dbg) {
3440 			id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3441 
3442 			id16_map_dbg->total = total_ids;
3443 			for (idx = 0; idx < total_ids; idx++) {
3444 				id16_map_dbg->avail[idx] = TRUE;
3445 			}
3446 		}
3447 	}
3448 #endif /* BCM_DBG && BCM_DBG_ID16 */
3449 }
3450 
3451 uint16 BCMFASTPATH /* Allocate a unique 16bit id */
id16_map_alloc(void * id16_map_hndl)3452 id16_map_alloc(void * id16_map_hndl)
3453 {
3454 	uint16 val16;
3455 	id16_map_t * id16_map;
3456 
3457 	ASSERT(id16_map_hndl != NULL);
3458 
3459 	id16_map = (id16_map_t *)id16_map_hndl;
3460 
3461 	ASSERT(id16_map->total > 0);
3462 
3463 	if (id16_map->stack_idx < 0) {
3464 		id16_map->failures++;
3465 		return ID16_INVALID;
3466 	}
3467 
3468 	val16 = id16_map->stack[id16_map->stack_idx];
3469 	id16_map->stack_idx--;
3470 
3471 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3472 	ASSERT((id16_map->start == ID16_UNDEFINED) ||
3473 	       (val16 < (id16_map->start + id16_map->total)));
3474 
3475 	if (id16_map->dbg) { /* Validate val16 */
3476 		id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3477 
3478 		ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
3479 		id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
3480 	}
3481 #endif /* BCM_DBG && BCM_DBG_ID16 */
3482 
3483 	return val16;
3484 }
3485 
3486 
3487 void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
id16_map_free(void * id16_map_hndl,uint16 val16)3488 id16_map_free(void * id16_map_hndl, uint16 val16)
3489 {
3490 	id16_map_t * id16_map;
3491 
3492 	ASSERT(id16_map_hndl != NULL);
3493 
3494 	id16_map = (id16_map_t *)id16_map_hndl;
3495 
3496 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3497 	ASSERT((id16_map->start == ID16_UNDEFINED) ||
3498 	       (val16 < (id16_map->start + id16_map->total)));
3499 
3500 	if (id16_map->dbg) { /* Validate val16 */
3501 		id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3502 
3503 		ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
3504 		id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
3505 	}
3506 #endif /* BCM_DBG && BCM_DBG_ID16 */
3507 
3508 	id16_map->stack_idx++;
3509 	id16_map->stack[id16_map->stack_idx] = val16;
3510 }
3511 
3512 uint32 /* Returns number of failures to allocate an unique id16 */
id16_map_failures(void * id16_map_hndl)3513 id16_map_failures(void * id16_map_hndl)
3514 {
3515 	ASSERT(id16_map_hndl != NULL);
3516 	return ((id16_map_t *)id16_map_hndl)->failures;
3517 }
3518 
3519 bool
id16_map_audit(void * id16_map_hndl)3520 id16_map_audit(void * id16_map_hndl)
3521 {
3522 	int idx;
3523 	int insane = 0;
3524 	id16_map_t * id16_map;
3525 
3526 	ASSERT(id16_map_hndl != NULL);
3527 
3528 	id16_map = (id16_map_t *)id16_map_hndl;
3529 
3530 	ASSERT(id16_map->stack_idx >= -1);
3531 	ASSERT(id16_map->stack_idx < (int)id16_map->total);
3532 
3533 	if (id16_map->start == ID16_UNDEFINED)
3534 		goto done;
3535 
3536 	for (idx = 0; idx <= id16_map->stack_idx; idx++) {
3537 		ASSERT(id16_map->stack[idx] >= id16_map->start);
3538 		ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
3539 
3540 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3541 		if (id16_map->dbg) {
3542 			uint16 val16 = id16_map->stack[idx];
3543 			if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
3544 				insane |= 1;
3545 				ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
3546 					id16_map_hndl, idx, val16));
3547 			}
3548 		}
3549 #endif /* BCM_DBG && BCM_DBG_ID16 */
3550 	}
3551 
3552 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3553 	if (id16_map->dbg) {
3554 		uint16 avail = 0; /* Audit available ids counts */
3555 		for (idx = 0; idx < id16_map_dbg->total; idx++) {
3556 			if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
3557 				avail++;
3558 		}
3559 		if (avail && (avail != (id16_map->stack_idx + 1))) {
3560 			insane |= 1;
3561 			ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
3562 				id16_map_hndl, avail, id16_map->stack_idx));
3563 		}
3564 	}
3565 #endif /* BCM_DBG && BCM_DBG_ID16 */
3566 
3567 done:
3568 	/* invoke any other system audits */
3569 	return (!!insane);
3570 }
3571 /* END: Simple id16 allocator */
3572 
3573 
3574 #endif
3575 
3576 /* calculate a >> b; and returns only lower 32 bits */
3577 void
bcm_uint64_right_shift(uint32 * r,uint32 a_high,uint32 a_low,uint32 b)3578 bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
3579 {
3580 	uint32 a1 = a_high, a0 = a_low, r0 = 0;
3581 
3582 	if (b == 0) {
3583 		r0 = a_low;
3584 		*r = r0;
3585 		return;
3586 	}
3587 
3588 	if (b < 32) {
3589 		a0 = a0 >> b;
3590 		a1 = a1 & ((1 << b) - 1);
3591 		a1 = a1 << (32 - b);
3592 		r0 = a0 | a1;
3593 		*r = r0;
3594 		return;
3595 	} else {
3596 		r0 = a1 >> (b - 32);
3597 		*r = r0;
3598 		return;
3599 	}
3600 
3601 }
3602 
3603 /* calculate a + b where a is a 64 bit number and b is a 32 bit number */
3604 void
bcm_add_64(uint32 * r_hi,uint32 * r_lo,uint32 offset)3605 bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset)
3606 {
3607 	uint32 r1_lo = *r_lo;
3608 	(*r_lo) += offset;
3609 	if (*r_lo < r1_lo)
3610 		(*r_hi) ++;
3611 }
3612 
3613 /* calculate a - b where a is a 64 bit number and b is a 32 bit number */
3614 void
bcm_sub_64(uint32 * r_hi,uint32 * r_lo,uint32 offset)3615 bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset)
3616 {
3617 	uint32 r1_lo = *r_lo;
3618 	(*r_lo) -= offset;
3619 	if (*r_lo > r1_lo)
3620 		(*r_hi) --;
3621 }
3622 
3623 /* Does unsigned 64 bit fixed point multiplication */
3624 uint64
fp_mult_64(uint64 val1,uint64 val2,uint8 nf1,uint8 nf2,uint8 nf_res)3625 fp_mult_64(uint64 val1, uint64 val2, uint8 nf1, uint8 nf2, uint8 nf_res)
3626 {
3627 	uint64 mult_out_tmp, mult_out, rnd_val;
3628 	uint8 shift_amt;
3629 
3630 	shift_amt = nf1 + nf2 - nf_res;
3631 	/* 0.5 in 1.0.shift_amt */
3632 	rnd_val = bcm_shl_64(1, (shift_amt - 1));
3633 	rnd_val = (shift_amt == 0) ? 0 : rnd_val;
3634 	mult_out_tmp = (uint64)((uint64)val1 * (uint64)val2) + (uint64)rnd_val;
3635 	mult_out = bcm_shr_64(mult_out_tmp, shift_amt);
3636 
3637 	return mult_out;
3638 }
3639 
3640 
3641 /* Does unsigned 64 bit by 32 bit fixed point division */
3642 uint8
fp_div_64(uint64 num,uint32 den,uint8 nf_num,uint8 nf_den,uint32 * div_out)3643 fp_div_64(uint64 num, uint32 den, uint8 nf_num, uint8 nf_den, uint32 *div_out)
3644 {
3645 	uint8 shift_amt1, shift_amt2, shift_amt, nf_res, hd_rm_nr, hd_rm_dr;
3646 	uint32 num_hi, num_lo;
3647 	uint64 num_scale;
3648 
3649 	/* Worst case shift possible */
3650 	hd_rm_nr = fp_calc_head_room_64(num);
3651 	hd_rm_dr = fp_calc_head_room_32(den);
3652 
3653 	/* (Nr / Dr) <= 2^32 */
3654 	shift_amt1 = hd_rm_nr - hd_rm_dr - 1;
3655 	/* Shift <= 32 + N2 - N1 */
3656 	shift_amt2 = 31 + nf_den - nf_num;
3657 	shift_amt = MINIMUM(shift_amt1, shift_amt2);
3658 
3659 	/* Scale numerator */
3660 	num_scale = bcm_shl_64(num, shift_amt);
3661 
3662 	/* Do division */
3663 	num_hi = (uint32)((uint64)num_scale >> 32) & MASK_32_BITS;
3664 	num_lo = (uint32)(num_scale & MASK_32_BITS);
3665 	bcm_uint64_divide(div_out, num_hi, num_lo, den);
3666 
3667 	/* Result format */
3668 	nf_res = nf_num - nf_den + shift_amt;
3669 	return nf_res;
3670 }
3671 
3672 /* Finds the number of bits available for shifting in unsigned 64 bit number */
3673 uint8
fp_calc_head_room_64(uint64 num)3674 fp_calc_head_room_64(uint64 num)
3675 {
3676 	uint8 n_room_bits = 0, msb_pos;
3677 	uint32 num_hi, num_lo, x;
3678 
3679 	num_hi = (uint32)((uint64)num >> 32) & MASK_32_BITS;
3680 	num_lo = (uint32)(num & MASK_32_BITS);
3681 
3682 	if (num_hi > 0) {
3683 		x = num_hi;
3684 		n_room_bits = 0;
3685 	} else {
3686 		x = num_lo;
3687 		n_room_bits = 32;
3688 	}
3689 
3690 	msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS])
3691 			: (16 + msb_table[(x >> 16) & MASK_8_BITS]))
3692 			: ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS])
3693 			: msb_table[x & MASK_8_BITS]);
3694 
3695 	return (n_room_bits + 32 - msb_pos);
3696 }
3697 
3698 /* Finds the number of bits available for shifting in unsigned 32 bit number */
3699 uint8
fp_calc_head_room_32(uint32 x)3700 fp_calc_head_room_32(uint32 x)
3701 {
3702 	uint8 msb_pos;
3703 
3704 	msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS])
3705 			: (16 + msb_table[(x >> 16) & MASK_8_BITS]))
3706 			: ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS])
3707 			: msb_table[x & MASK_8_BITS]);
3708 
3709 	return (32 - msb_pos);
3710 }
3711 
3712 /* Does unsigned 64 bit fixed point floor */
3713 uint32
fp_floor_64(uint64 num,uint8 floor_pos)3714 fp_floor_64(uint64 num, uint8 floor_pos)
3715 {
3716 	uint32 floor_out;
3717 
3718 	floor_out = (uint32)bcm_shr_64(num, floor_pos);
3719 
3720 	return floor_out;
3721 }
3722 
3723 /* Does unsigned 32 bit fixed point floor */
3724 uint32
fp_floor_32(uint32 num,uint8 floor_pos)3725 fp_floor_32(uint32 num, uint8 floor_pos)
3726 {
3727 	return num >> floor_pos;
3728 }
3729 
3730 /* Does unsigned 64 bit fixed point rounding */
3731 uint32
fp_round_64(uint64 num,uint8 rnd_pos)3732 fp_round_64(uint64 num, uint8 rnd_pos)
3733 {
3734 	uint64 rnd_val, rnd_out_tmp;
3735 	uint32 rnd_out;
3736 
3737 	/* 0.5 in 1.0.rnd_pos */
3738 	rnd_val = bcm_shl_64(1, (rnd_pos - 1));
3739 	rnd_val = (rnd_pos == 0) ? 0 : rnd_val;
3740 	rnd_out_tmp = num + rnd_val;
3741 	rnd_out = (uint32)bcm_shr_64(rnd_out_tmp, rnd_pos);
3742 
3743 	return rnd_out;
3744 }
3745 
3746 /* Does unsigned 32 bit fixed point rounding */
3747 uint32
fp_round_32(uint32 num,uint8 rnd_pos)3748 fp_round_32(uint32 num, uint8 rnd_pos)
3749 {
3750 	uint32 rnd_val, rnd_out_tmp;
3751 
3752 	/* 0.5 in 1.0.rnd_pos */
3753 	rnd_val = 1 << (rnd_pos - 1);
3754 	rnd_val = (rnd_pos == 0) ? 0 : rnd_val;
3755 	rnd_out_tmp = num + rnd_val;
3756 	return (rnd_out_tmp >> rnd_pos);
3757 }
3758 
3759 /* Does unsigned fixed point ceiling */
3760 uint32
fp_ceil_64(uint64 num,uint8 ceil_pos)3761 fp_ceil_64(uint64 num, uint8 ceil_pos)
3762 {
3763 	uint64 ceil_val, ceil_out_tmp;
3764 	uint32 ceil_out;
3765 
3766 	/* 0.999 in 1.0.rnd_pos */
3767 	ceil_val = bcm_shl_64(1, ceil_pos) - 1;
3768 	ceil_out_tmp = num + ceil_val;
3769 	ceil_out = (uint32)bcm_shr_64(ceil_out_tmp, ceil_pos);
3770 
3771 	return ceil_out;
3772 }
3773 
3774 /* Does left shift of unsigned 64 bit number */
3775 uint64
bcm_shl_64(uint64 input,uint8 shift_amt)3776 bcm_shl_64(uint64 input, uint8 shift_amt)
3777 {
3778 	uint32 in_hi, in_lo;
3779 	uint32 masked_lo = 0;
3780 	uint32 mask;
3781 	uint64 shl_out;
3782 
3783 	if (shift_amt == 0) {
3784 		return input;
3785 	}
3786 
3787 	/* Get hi and lo part */
3788 	in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS;
3789 	in_lo = (uint32)(input & MASK_32_BITS);
3790 
3791 	if (shift_amt < 32) {
3792 		/* Extract bit which belongs to hi part after shifting */
3793 		mask = ((uint32)~0) << (32 - shift_amt);
3794 		masked_lo = (in_lo & mask) >> (32 - shift_amt);
3795 
3796 		/* Shift hi and lo and prepare output */
3797 		in_hi = (in_hi << shift_amt) | masked_lo;
3798 		in_lo = in_lo << shift_amt;
3799 	} else {
3800 		/* Extract bit which belongs to hi part after shifting */
3801 		shift_amt = shift_amt - 32;
3802 
3803 		/* Shift hi and lo and prepare output */
3804 		in_hi = in_lo << shift_amt;
3805 		in_lo = 0;
3806 	}
3807 
3808 	shl_out = (((uint64)in_hi << 32) | in_lo);
3809 	return shl_out;
3810 }
3811 
3812 /* Does right shift of unsigned 64 bit number */
3813 uint64
bcm_shr_64(uint64 input,uint8 shift_amt)3814 bcm_shr_64(uint64 input, uint8 shift_amt)
3815 {
3816 	uint32 in_hi, in_lo;
3817 	uint32 masked_hi = 0;
3818 	uint32 mask;
3819 	uint64 shr_out;
3820 
3821 	if (shift_amt == 0) {
3822 		return input;
3823 	}
3824 
3825 	/* Get hi and lo part */
3826 	in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS;
3827 	in_lo = (uint32)(input & MASK_32_BITS);
3828 
3829 	if (shift_amt < 32) {
3830 		/* Extract bit which belongs to lo part after shifting */
3831 		mask = (1 << shift_amt) - 1;
3832 		masked_hi = in_hi & mask;
3833 
3834 		/* Shift hi and lo and prepare output */
3835 		in_hi = (uint32)in_hi >> shift_amt;
3836 		in_lo = ((uint32)in_lo >> shift_amt) | (masked_hi << (32 - shift_amt));
3837 	} else {
3838 		shift_amt = shift_amt - 32;
3839 		in_lo = in_hi >> shift_amt;
3840 		in_hi = 0;
3841 	}
3842 
3843 	shr_out = (((uint64)in_hi << 32) | in_lo);
3844 	return shr_out;
3845 }
3846 
3847 #ifdef DEBUG_COUNTER
3848 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
counter_printlog(counter_tbl_t * ctr_tbl)3849 void counter_printlog(counter_tbl_t *ctr_tbl)
3850 {
3851 	uint32 now;
3852 
3853 	if (!ctr_tbl->enabled)
3854 		return;
3855 
3856 	now = OSL_SYSUPTIME();
3857 
3858 	if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) {
3859 		uint8 i = 0;
3860 		printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print);
3861 
3862 		for (i = 0; i < ctr_tbl->needed_cnt; i++) {
3863 			printf(" %u", ctr_tbl->cnt[i]);
3864 		}
3865 		printf("\n");
3866 
3867 		ctr_tbl->prev_log_print = now;
3868 		bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint));
3869 	}
3870 }
3871 #else
3872 /* OSL_SYSUPTIME is not supported so no way to get time */
3873 #define counter_printlog(a) do {} while (0)
3874 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
3875 #endif /* DEBUG_COUNTER */
3876 
3877 #if defined(BCMDRIVER) && !defined(_CFEZ_)
3878 void
dll_pool_detach(void * osh,dll_pool_t * pool,uint16 elems_max,uint16 elem_size)3879 dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
3880 {
3881 	uint32 mem_size;
3882 	mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
3883 	if (pool)
3884 		MFREE(osh, pool, mem_size);
3885 }
3886 dll_pool_t *
dll_pool_init(void * osh,uint16 elems_max,uint16 elem_size)3887 dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size)
3888 {
3889 	uint32 mem_size, i;
3890 	dll_pool_t * dll_pool_p;
3891 	dll_t * elem_p;
3892 
3893 	ASSERT(elem_size > sizeof(dll_t));
3894 
3895 	mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
3896 
3897 	if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) {
3898 		printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
3899 			elems_max, elem_size);
3900 		ASSERT(0);
3901 		return dll_pool_p;
3902 	}
3903 
3904 	dll_init(&dll_pool_p->free_list);
3905 	dll_pool_p->elems_max = elems_max;
3906 	dll_pool_p->elem_size = elem_size;
3907 
3908 	elem_p = dll_pool_p->elements;
3909 	for (i = 0; i < elems_max; i++) {
3910 		dll_append(&dll_pool_p->free_list, elem_p);
3911 		elem_p = (dll_t *)((uintptr)elem_p + elem_size);
3912 	}
3913 
3914 	dll_pool_p->free_count = elems_max;
3915 
3916 	return dll_pool_p;
3917 }
3918 
3919 
3920 void *
dll_pool_alloc(dll_pool_t * dll_pool_p)3921 dll_pool_alloc(dll_pool_t * dll_pool_p)
3922 {
3923 	dll_t * elem_p;
3924 
3925 	if (dll_pool_p->free_count == 0) {
3926 		ASSERT(dll_empty(&dll_pool_p->free_list));
3927 		return NULL;
3928 	}
3929 
3930 	elem_p = dll_head_p(&dll_pool_p->free_list);
3931 	dll_delete(elem_p);
3932 	dll_pool_p->free_count -= 1;
3933 
3934 	return (void *)elem_p;
3935 }
3936 
3937 void
dll_pool_free(dll_pool_t * dll_pool_p,void * elem_p)3938 dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p)
3939 {
3940 	dll_t * node_p = (dll_t *)elem_p;
3941 	dll_prepend(&dll_pool_p->free_list, node_p);
3942 	dll_pool_p->free_count += 1;
3943 }
3944 
3945 
3946 void
dll_pool_free_tail(dll_pool_t * dll_pool_p,void * elem_p)3947 dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
3948 {
3949 	dll_t * node_p = (dll_t *)elem_p;
3950 	dll_append(&dll_pool_p->free_list, node_p);
3951 	dll_pool_p->free_count += 1;
3952 }
3953 
3954 #endif
3955 
3956 /* calculate partial checksum */
3957 static uint32
ip_cksum_partial(uint32 sum,uint8 * val8,uint32 count)3958 ip_cksum_partial(uint32 sum, uint8 *val8, uint32 count)
3959 {
3960 	uint32 i;
3961 	uint16 *val16 = (uint16 *)val8;
3962 
3963 	ASSERT(val8 != NULL);
3964 	/* partial chksum calculated on 16-bit values */
3965 	ASSERT((count % 2) == 0);
3966 
3967 	count /= 2;
3968 
3969 	for (i = 0; i < count; i++) {
3970 		sum += *val16++;
3971 	}
3972 	return sum;
3973 }
3974 
3975 /* calculate IP checksum */
3976 static uint16
ip_cksum(uint32 sum,uint8 * val8,uint32 count)3977 ip_cksum(uint32 sum, uint8 *val8, uint32 count)
3978 {
3979 	uint16 *val16 = (uint16 *)val8;
3980 
3981 	ASSERT(val8 != NULL);
3982 
3983 	while (count > 1) {
3984 		sum += *val16++;
3985 		count -= 2;
3986 	}
3987 	/*  add left-over byte, if any */
3988 	if (count > 0) {
3989 		sum += (*(uint8 *)val16);
3990 	}
3991 
3992 	/*  fold 32-bit sum to 16 bits */
3993 	sum = (sum >> 16) + (sum & 0xffff);
3994 	sum += (sum >> 16);
3995 	return ((uint16)~sum);
3996 }
3997 
3998 /* calculate IPv4 header checksum
3999  * - input ip points to IP header in network order
4000  * - output cksum is in network order
4001  */
4002 uint16
ipv4_hdr_cksum(uint8 * ip,int ip_len)4003 ipv4_hdr_cksum(uint8 *ip, int ip_len)
4004 {
4005 	uint32 sum = 0;
4006 	uint8 *ptr = ip;
4007 
4008 	ASSERT(ip != NULL);
4009 	ASSERT(ip_len >= IPV4_MIN_HEADER_LEN);
4010 
4011 	/* partial cksum skipping the hdr_chksum field */
4012 	sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct ipv4_hdr, hdr_chksum));
4013 	ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2;
4014 
4015 	/* return calculated chksum */
4016 	return ip_cksum(sum, ptr, ip_len - OFFSETOF(struct ipv4_hdr, src_ip));
4017 }
4018 
4019 /* calculate TCP header checksum using partial sum */
4020 static uint16
tcp_hdr_chksum(uint32 sum,uint8 * tcp_hdr,uint16 tcp_len)4021 tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len)
4022 {
4023 	uint8 *ptr = tcp_hdr;
4024 
4025 	ASSERT(tcp_hdr != NULL);
4026 	ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
4027 
4028 	/* partial TCP cksum skipping the chksum field */
4029 	sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum));
4030 	ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2;
4031 
4032 	/* return calculated chksum */
4033 	return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr));
4034 }
4035 
4036 struct tcp_pseudo_hdr {
4037 	uint8   src_ip[IPV4_ADDR_LEN];  /* Source IP Address */
4038 	uint8   dst_ip[IPV4_ADDR_LEN];  /* Destination IP Address */
4039 	uint8	zero;
4040 	uint8	prot;
4041 	uint16	tcp_size;
4042 };
4043 
4044 /* calculate IPv4 TCP header checksum
4045  * - input ip and tcp points to IP and TCP header in network order
4046  * - output cksum is in network order
4047  */
4048 uint16
ipv4_tcp_hdr_cksum(uint8 * ip,uint8 * tcp,uint16 tcp_len)4049 ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len)
4050 {
4051 	struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip;
4052 	struct tcp_pseudo_hdr tcp_ps;
4053 	uint32 sum = 0;
4054 
4055 	ASSERT(ip != NULL);
4056 	ASSERT(tcp != NULL);
4057 	ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
4058 
4059 	/* pseudo header cksum */
4060 	memset(&tcp_ps, 0, sizeof(tcp_ps));
4061 	memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN);
4062 	memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN);
4063 	tcp_ps.zero = 0;
4064 	tcp_ps.prot = ip_hdr->prot;
4065 	tcp_ps.tcp_size = hton16(tcp_len);
4066 	sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps));
4067 
4068 	/* return calculated TCP header chksum */
4069 	return tcp_hdr_chksum(sum, tcp, tcp_len);
4070 }
4071 
4072 struct ipv6_pseudo_hdr {
4073 	uint8  saddr[IPV6_ADDR_LEN];
4074 	uint8  daddr[IPV6_ADDR_LEN];
4075 	uint16 payload_len;
4076 	uint8  zero;
4077 	uint8  next_hdr;
4078 };
4079 
4080 /* calculate IPv6 TCP header checksum
4081  * - input ipv6 and tcp points to IPv6 and TCP header in network order
4082  * - output cksum is in network order
4083  */
4084 uint16
ipv6_tcp_hdr_cksum(uint8 * ipv6,uint8 * tcp,uint16 tcp_len)4085 ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len)
4086 {
4087 	struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6;
4088 	struct ipv6_pseudo_hdr ipv6_pseudo;
4089 	uint32 sum = 0;
4090 
4091 	ASSERT(ipv6 != NULL);
4092 	ASSERT(tcp != NULL);
4093 	ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
4094 
4095 	/* pseudo header cksum */
4096 	memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo));
4097 	memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr,
4098 		sizeof(ipv6_pseudo.saddr));
4099 	memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr,
4100 		sizeof(ipv6_pseudo.daddr));
4101 	ipv6_pseudo.payload_len = ipv6_hdr->payload_len;
4102 	ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr;
4103 	sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo));
4104 
4105 	/* return calculated TCP header chksum */
4106 	return tcp_hdr_chksum(sum, tcp, tcp_len);
4107 }
4108