www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / bcmdrivers / broadcom / net / wl / impl2 / shared / bcmutils.c
1 /*
2  * Driver O/S-independent utility routines
3  *
4  * Copyright 2006, Broadcom Corporation
5  * All Rights Reserved.
6  * 
7  * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8  * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9  * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10  * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11  * $Id$
12  */
13
14 #include <typedefs.h>
15 #include <bcmdefs.h>
16 #include <stdarg.h>
17 #include <bcmutils.h>
18 #ifdef BCMDRIVER
19 #include <osl.h>
20 #include <sbutils.h>
21 #include <bcmnvram.h>
22 #else
23 #include <stdio.h>
24 #include <string.h>
25 #endif /* BCMDRIVER */
26 #if defined(NDIS) || defined(__vxworks) || defined(_CFE_)
27 /* debatable */
28 #include <bcmstdlib.h>
29 #endif 
30 #include <bcmendian.h>
31 #include <bcmdevs.h>
32 #include <proto/ethernet.h>
33 #include <proto/vlan.h>
34 #include <proto/bcmip.h>
35 #include <proto/802.1d.h>
36
37 #ifdef BCMPERFSTATS
38 #include <bcmperf.h>
39 #endif
40
41 #ifdef BCMDRIVER
42 /* nvram vars cache */
43 static char *nvram_vars = NULL;
44 static int vars_len = -1;
45
46 /* copy a pkt buffer chain into a buffer */
47 uint
48 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
49 {
50         uint n, ret = 0;
51
52         if (len < 0)
53                 len = 4096;     /* "infinite" */
54
55         /* skip 'offset' bytes */
56         for (; p && offset; p = PKTNEXT(osh, p)) {
57                 if (offset < (uint)PKTLEN(osh, p))
58                         break;
59                 offset -= PKTLEN(osh, p);
60         }
61
62         if (!p)
63                 return 0;
64
65         /* copy the data */
66         for (; p && len; p = PKTNEXT(osh, p)) {
67                 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
68                 bcopy(PKTDATA(osh, p) + offset, buf, n);
69                 buf += n;
70                 len -= n;
71                 ret += n;
72                 offset = 0;
73         }
74
75         return ret;
76 }
77
78 /* return total length of buffer chain */
79 uint
80 pkttotlen(osl_t *osh, void *p)
81 {
82         uint total;
83
84         total = 0;
85         for (; p; p = PKTNEXT(osh, p))
86                 total += PKTLEN(osh, p);
87         return (total);
88 }
89
90 /* return the last buffer of chained pkt */
91 void *
92 pktlast(osl_t *osh, void *p)
93 {
94         for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
95                 ;
96
97         return (p);
98 }
99
100
101 /*
102  * osl multiple-precedence packet queue
103  * hi_prec is always >= the number of the highest non-empty queue
104  */
105 void *
106 pktq_penq(struct pktq *pq, int prec, void *p)
107 {
108         struct pktq_prec *q;
109
110         ASSERT(prec >= 0 && prec < pq->num_prec);
111         ASSERT(PKTLINK(p) == NULL);         /* queueing chains not allowed */
112
113         ASSERT(!pktq_full(pq));
114         ASSERT(!pktq_pfull(pq, prec));
115
116         q = &pq->q[prec];
117
118         if (q->head)
119                 PKTSETLINK(q->tail, p);
120         else
121                 q->head = p;
122
123         q->tail = p;
124         q->len++;
125
126         pq->len++;
127
128         if (pq->hi_prec < prec)
129                 pq->hi_prec = (uint8)prec;
130
131         return p;
132 }
133
134 void *
135 pktq_penq_head(struct pktq *pq, int prec, void *p)
136 {
137         struct pktq_prec *q;
138
139         ASSERT(prec >= 0 && prec < pq->num_prec);
140         ASSERT(PKTLINK(p) == NULL);         /* queueing chains not allowed */
141
142         ASSERT(!pktq_full(pq));
143         ASSERT(!pktq_pfull(pq, prec));
144
145         q = &pq->q[prec];
146
147         if (q->head == NULL)
148                 q->tail = p;
149
150         PKTSETLINK(p, q->head);
151         q->head = p;
152         q->len++;
153
154         pq->len++;
155
156         if (pq->hi_prec < prec)
157                 pq->hi_prec = (uint8)prec;
158
159         return p;
160 }
161
162 void *
163 pktq_pdeq(struct pktq *pq, int prec)
164 {
165         struct pktq_prec *q;
166         void *p;
167
168         ASSERT(prec >= 0 && prec < pq->num_prec);
169
170         q = &pq->q[prec];
171
172         if ((p = q->head) == NULL)
173                 return NULL;
174
175         if ((q->head = PKTLINK(p)) == NULL)
176                 q->tail = NULL;
177
178         q->len--;
179
180         pq->len--;
181
182         PKTSETLINK(p, NULL);
183
184         return p;
185 }
186
187 void *
188 pktq_pdeq_tail(struct pktq *pq, int prec)
189 {
190         struct pktq_prec *q;
191         void *p, *prev;
192
193         ASSERT(prec >= 0 && prec < pq->num_prec);
194
195         q = &pq->q[prec];
196
197         if ((p = q->head) == NULL)
198                 return NULL;
199
200         for (prev = NULL; p != q->tail; p = PKTLINK(p))
201                 prev = p;
202
203         if (prev)
204                 PKTSETLINK(prev, NULL);
205         else
206                 q->head = NULL;
207
208         q->tail = prev;
209         q->len--;
210
211         pq->len--;
212
213         return p;
214 }
215
216 void
217 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
218 {
219         struct pktq_prec *q;
220         void *p;
221
222         q = &pq->q[prec];
223         p = q->head;
224         while (p) {
225                 q->head = PKTLINK(p);
226                 PKTSETLINK(p, NULL);
227                 PKTFREE(osh, p, dir);
228                 q->len--;
229                 pq->len--;
230                 p = q->head;
231         }
232         ASSERT(q->len == 0);
233         q->tail = NULL;
234 }
235
236 bool
237 pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
238 {
239         struct pktq_prec *q;
240         void *p;
241
242         ASSERT(prec >= 0 && prec < pq->num_prec);
243
244         if (!pktbuf)
245                 return FALSE;
246
247         q = &pq->q[prec];
248
249         if (q->head == pktbuf) {
250                 if ((q->head = PKTLINK(pktbuf)) == NULL)
251                         q->tail = NULL;
252         } else {
253                 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
254                         ;
255                 if (p == NULL)
256                         return FALSE;
257
258                 PKTSETLINK(p, PKTLINK(pktbuf));
259                 if (q->tail == pktbuf)
260                         q->tail = p;
261         }
262
263         q->len--;
264         pq->len--;
265         PKTSETLINK(pktbuf, NULL);
266         return TRUE;
267 }
268
269 void
270 pktq_init(struct pktq *pq, int num_prec, int max_len)
271 {
272         int prec;
273
274         ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
275
276         /* pq is variable size; only zero out what's requested */
277         bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
278
279         pq->num_prec = (uint16)num_prec;
280
281         pq->max = (uint16)max_len;
282
283         for (prec = 0; prec < num_prec; prec++)
284                 pq->q[prec].max = pq->max;
285 }
286
287 void *
288 pktq_deq(struct pktq *pq, int *prec_out)
289 {
290         struct pktq_prec *q;
291         void *p;
292         int prec;
293
294         if (pq->len == 0)
295                 return NULL;
296
297         while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
298                 pq->hi_prec--;
299
300         q = &pq->q[prec];
301
302         if ((p = q->head) == NULL)
303                 return NULL;
304
305         if ((q->head = PKTLINK(p)) == NULL)
306                 q->tail = NULL;
307
308         q->len--;
309
310         pq->len--;
311
312         if (prec_out)
313                 *prec_out = prec;
314
315         PKTSETLINK(p, NULL);
316
317         return p;
318 }
319
320 void *
321 pktq_deq_tail(struct pktq *pq, int *prec_out)
322 {
323         struct pktq_prec *q;
324         void *p, *prev;
325         int prec;
326
327         if (pq->len == 0)
328                 return NULL;
329
330         for (prec = 0; prec < pq->hi_prec; prec++)
331                 if (pq->q[prec].head)
332                         break;
333
334         q = &pq->q[prec];
335
336         if ((p = q->head) == NULL)
337                 return NULL;
338
339         for (prev = NULL; p != q->tail; p = PKTLINK(p))
340                 prev = p;
341
342         if (prev)
343                 PKTSETLINK(prev, NULL);
344         else
345                 q->head = NULL;
346
347         q->tail = prev;
348         q->len--;
349
350         pq->len--;
351
352         if (prec_out)
353                 *prec_out = prec;
354
355         PKTSETLINK(p, NULL);
356
357         return p;
358 }
359
360 void *
361 pktq_peek(struct pktq *pq, int *prec_out)
362 {
363         int prec;
364
365         if (pq->len == 0)
366                 return NULL;
367
368         while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
369                 pq->hi_prec--;
370
371         if (prec_out)
372                 *prec_out = prec;
373
374         return (pq->q[prec].head);
375 }
376
377 void *
378 pktq_peek_tail(struct pktq *pq, int *prec_out)
379 {
380         int prec;
381
382         if (pq->len == 0)
383                 return NULL;
384
385         for (prec = 0; prec < pq->hi_prec; prec++)
386                 if (pq->q[prec].head)
387                         break;
388
389         if (prec_out)
390                 *prec_out = prec;
391
392         return (pq->q[prec].tail);
393 }
394
395 void
396 pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
397 {
398         int prec;
399         for (prec = 0; prec < pq->num_prec; prec++)
400                 pktq_pflush(osh, pq, prec, dir);
401         ASSERT(pq->len == 0);
402 }
403
404 /* Return sum of lengths of a specific set of precedences */
405 int
406 pktq_mlen(struct pktq *pq, uint prec_bmp)
407 {
408         int prec, len;
409
410         len = 0;
411
412         for (prec = 0; prec <= pq->hi_prec; prec++)
413                 if (prec_bmp & (1 << prec))
414                         len += pq->q[prec].len;
415
416         return len;
417 }
418
419 /* Priority dequeue from a specific set of precedences */
420 void *
421 pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
422 {
423         struct pktq_prec *q;
424         void *p;
425         int prec;
426
427         if (pq->len == 0)
428                 return NULL;
429
430         while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
431                 pq->hi_prec--;
432
433         while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
434                 if (prec-- == 0)
435                         return NULL;
436
437         q = &pq->q[prec];
438
439         if ((p = q->head) == NULL)
440                 return NULL;
441
442         if ((q->head = PKTLINK(p)) == NULL)
443                 q->tail = NULL;
444
445         q->len--;
446
447         if (prec_out)
448                 *prec_out = prec;
449
450         pq->len--;
451
452         PKTSETLINK(p, NULL);
453
454         return p;
455 }
456
457 #ifndef BCMROMOFFLOAD
458
459 const unsigned char bcm_ctype[] = {
460         _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,                        /* 0-7 */
461         _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
462         _BCM_C, /* 8-15 */
463         _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,                        /* 16-23 */
464         _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,                        /* 24-31 */
465         _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,                /* 32-39 */
466         _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,                        /* 40-47 */
467         _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,                        /* 48-55 */
468         _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,                        /* 56-63 */
469         _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
470         _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
471         _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,                        /* 72-79 */
472         _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,                        /* 80-87 */
473         _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,                        /* 88-95 */
474         _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
475         _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
476         _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
477         _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
478         _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
479         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,         /* 128-143 */
480         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,         /* 144-159 */
481         _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
482         _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
483         _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
484         _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
485         _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
486         _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
487         _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
488         _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
489         _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
490         _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
491         _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
492         _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
493 };
494
495 ulong
496 BCMROMFN(bcm_strtoul)(char *cp, char **endp, uint base)
497 {
498         ulong result, value;
499         bool minus;
500
501         minus = FALSE;
502
503         while (bcm_isspace(*cp))
504                 cp++;
505
506         if (cp[0] == '+')
507                 cp++;
508         else if (cp[0] == '-') {
509                 minus = TRUE;
510                 cp++;
511         }
512
513         if (base == 0) {
514                 if (cp[0] == '0') {
515                         if ((cp[1] == 'x') || (cp[1] == 'X')) {
516                                 base = 16;
517                                 cp = &cp[2];
518                         } else {
519                                 base = 8;
520                                 cp = &cp[1];
521                         }
522                 } else
523                         base = 10;
524         } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
525                 cp = &cp[2];
526         }
527
528         result = 0;
529
530         while (bcm_isxdigit(*cp) &&
531                (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
532                 result = result*base + value;
533                 cp++;
534         }
535
536         if (minus)
537                 result = (ulong)(result * -1);
538
539         if (endp)
540                 *endp = (char *)cp;
541
542         return (result);
543 }
544
545 int
546 BCMROMFN(bcm_atoi)(char *s)
547 {
548         return (int)bcm_strtoul(s, NULL, 10);
549 }
550
551 /* return pointer to location of substring 'needle' in 'haystack' */
552 char*
553 BCMROMFN(bcmstrstr)(char *haystack, char *needle)
554 {
555         int len, nlen;
556         int i;
557
558         if ((haystack == NULL) || (needle == NULL))
559                 return (haystack);
560
561         nlen = strlen(needle);
562         len = strlen(haystack) - nlen + 1;
563
564         for (i = 0; i < len; i++)
565                 if (bcmp(needle, &haystack[i], nlen) == 0)
566                         return (&haystack[i]);
567         return (NULL);
568 }
569
570 char*
571 BCMROMFN(bcmstrcat)(char *dest, const char *src)
572 {
573         strcpy(&dest[strlen(dest)], src);
574         return (dest);
575 }
576
577 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
578 int
579 BCMROMFN(bcm_ether_atoe)(char *p, struct ether_addr *ea)
580 {
581         int i = 0;
582
583         for (;;) {
584                 ea->octet[i++] = (char) bcm_strtoul(p, &p, 16);
585                 if (!*p++ || i == 6)
586                         break;
587         }
588
589         return (i == 6);
590 }
591 #endif  /* !BCMROMOFFLOAD */
592
593 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
594 /* registry routine buffer preparation utility functions:
595  * parameter order is like strncpy, but returns count
596  * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
597  */
598 ulong
599 wchar2ascii(
600         char *abuf,
601         ushort *wbuf,
602         ushort wbuflen,
603         ulong abuflen
604 )
605 {
606         ulong copyct = 1;
607         ushort i;
608
609         if (abuflen == 0)
610                 return 0;
611
612         /* wbuflen is in bytes */
613         wbuflen /= sizeof(ushort);
614
615         for (i = 0; i < wbuflen; ++i) {
616                 if (--abuflen == 0)
617                         break;
618                 *abuf++ = (char) *wbuf++;
619                 ++copyct;
620         }
621         *abuf = '\0';
622
623         return copyct;
624 }
625 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
626
627 char*
628 bcm_ether_ntoa(struct ether_addr *ea, char *buf)
629 {
630         sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
631                 ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff,
632                 ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff);
633         return (buf);
634 }
635
636 void
637 bcm_mdelay(uint ms)
638 {
639         uint i;
640
641         for (i = 0; i < ms; i++) {
642                 OSL_DELAY(1000);
643         }
644 }
645
646 /*
647  * Search the name=value vars for a specific one and return its value.
648  * Returns NULL if not found.
649  */
650 char *
651 getvar(char *vars, const char *name)
652 {
653 #ifdef  _MINOSL_
654         return NULL;
655 #else
656         char *s;
657         int len;
658
659         len = strlen(name);
660
661         /* first look in vars[] */
662         for (s = vars; s && *s;) {
663                 /* CSTYLED */
664                 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
665                         return (&s[len+1]);
666
667                 while (*s++)
668                         ;
669         }
670
671         /* then query nvram */
672         return (nvram_get(name));
673 #endif  /* _MINOSL_ */
674 }
675
676 /*
677  * Search the vars for a specific one and return its value as
678  * an integer. Returns 0 if not found.
679  */
680 int
681 getintvar(char *vars, const char *name)
682 {
683 #ifdef  _MINOSL_
684         return 0;
685 #else
686         char *val;
687
688         if ((val = getvar(vars, name)) == NULL)
689                 return (0);
690
691         return (bcm_strtoul(val, NULL, 0));
692 #endif  /* _MINOSL_ */
693 }
694
695
696 /* Search for token in comma separated token-string */
697 static int
698 findmatch(char *string, char *name)
699 {
700         uint len;
701         char *c;
702
703         len = strlen(name);
704         /* CSTYLED */
705         while ((c = strchr(string, ',')) != NULL) {
706                 if (len == (uint)(c - string) && !strncmp(string, name, len))
707                         return 1;
708                 string = c + 1;
709         }
710
711         return (!strcmp(string, name));
712 }
713
714 /* Return gpio pin number assigned to the named pin */
715 /*
716 * Variable should be in format:
717 *
718 *       gpio<N>=pin_name,pin_name
719 *
720 * This format allows multiple features to share the gpio with mutual
721 * understanding.
722 *
723 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
724 * and if def_pin is not used by others.
725 */
726 uint
727 getgpiopin(char *vars, char *pin_name, uint def_pin)
728 {
729         char name[] = "gpioXXXX";
730         char *val;
731         uint pin;
732
733         /* Go thru all possibilities till a match in pin name */
734         for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
735                 sprintf(name, "gpio%d", pin);
736                 val = getvar(vars, name);
737                 if (val && findmatch(val, pin_name))
738                         return pin;
739         }
740
741         if (def_pin != GPIO_PIN_NOTDEFINED) {
742                 /* make sure the default pin is not used by someone else */
743                 sprintf(name, "gpio%d", def_pin);
744                 if (getvar(vars, name)) {
745                         def_pin =  GPIO_PIN_NOTDEFINED;
746                 }
747         }
748
749         return def_pin;
750 }
751
752 #ifdef BCMPERFSTATS
753
754 #define LOGSIZE 256                     /* should be power of 2 to avoid div below */
755 static struct {
756         uint    cycles;
757         char    *fmt;
758         uint    a1;
759         uint    a2;
760 } logtab[LOGSIZE];
761
762 /* last entry logged  */
763 static uint logi = 0;
764 /* next entry to read */
765 static uint readi = 0;
766
767 void
768 bcm_perf_enable()
769 {
770         BCMPERF_ENABLE_INSTRCOUNT();
771         BCMPERF_ENABLE_ICACHE_MISS();
772         BCMPERF_ENABLE_ICACHE_HIT();
773 }
774
775 void
776 bcmlog(char *fmt, uint a1, uint a2)
777 {
778         static uint last = 0;
779         uint cycles, i;
780         OSL_GETCYCLES(cycles);
781
782         i = logi;
783
784         logtab[i].cycles = cycles - last;
785         logtab[i].fmt = fmt;
786         logtab[i].a1 = a1;
787         logtab[i].a2 = a2;
788
789         logi = (i + 1) % LOGSIZE;
790         last = cycles;
791 }
792
793
794 void
795 bcmstats(char *fmt)
796 {
797         static uint last = 0;
798         static uint32 ic_miss = 0;
799         static uint32 instr_count = 0;
800         uint32 ic_miss_cur;
801         uint32 instr_count_cur;
802         uint cycles, i;
803
804         OSL_GETCYCLES(cycles);
805         BCMPERF_GETICACHE_MISS(ic_miss_cur);
806         BCMPERF_GETINSTRCOUNT(instr_count_cur);
807
808         i = logi;
809
810         logtab[i].cycles = cycles - last;
811         logtab[i].a1 = ic_miss_cur - ic_miss;
812         logtab[i].a2 = instr_count_cur - instr_count;
813         logtab[i].fmt = fmt;
814
815         logi = (i + 1) % LOGSIZE;
816
817         last = cycles;
818         instr_count = instr_count_cur;
819         ic_miss = ic_miss_cur;
820 }
821
822
823 void
824 bcmdumplog(char *buf, int size)
825 {
826         char *limit, *line;
827         int j = 0;
828         int num;
829
830         limit = buf + size - 80;
831         *buf = '\0';
832
833         num = logi - readi;
834
835         if (num < 0)
836                 num += LOGSIZE;
837
838         /* print in chronological order */
839
840         for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
841                 if (logtab[readi].fmt == NULL)
842                     continue;
843                 line = buf;
844                 buf += sprintf(buf, "%d\t", logtab[readi].cycles);
845                 buf += sprintf(buf, logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
846                 buf += sprintf(buf, "\n");
847         }
848
849 }
850
851
852 /*
853  * Dump one log entry at a time.
854  * Return index of next entry or -1 when no more .
855  */
856 int
857 bcmdumplogent(char *buf, uint i)
858 {
859         bool hit;
860
861         /*
862          * If buf is NULL, return the starting index,
863          * interpreting i as the indicator of last 'i' entries to dump.
864          */
865         if (buf == NULL) {
866                 i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
867                 return ((logi - i) % LOGSIZE);
868         }
869
870         *buf = '\0';
871
872         ASSERT(i < LOGSIZE);
873
874         if (i == logi)
875                 return (-1);
876
877         hit = FALSE;
878         for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) {
879                 if (logtab[i].fmt == NULL)
880                         continue;
881                 buf += sprintf(buf, "%d: %d\t", i, logtab[i].cycles);
882                 buf += sprintf(buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
883                 buf += sprintf(buf, "\n");
884                 hit = TRUE;
885         }
886
887         return (i);
888 }
889
890 #endif  /* BCMPERFSTATS */
891
892 #ifdef BCMDBG
893 /* pretty hex print a pkt buffer chain */
894 void
895 prpkt(const char *msg, osl_t *osh, void *p0)
896 {
897         void *p;
898
899         if (msg && (msg[0] != '\0'))
900                 printf("%s:\n", msg);
901
902         for (p = p0; p; p = PKTNEXT(osh, p))
903                 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
904 }
905 #endif  /* BCMDBG */
906
907 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
908  * Also updates the inplace vlan tag if requested.
909  * For debugging, it returns an indication of what it did.
910  */
911 uint
912 pktsetprio(void *pkt, bool update_vtag)
913 {
914         struct ether_header *eh;
915         struct ethervlan_header *evh;
916         uint8 *pktdata;
917         int priority = 0;
918         int rc = 0;
919
920         pktdata = (uint8 *) PKTDATA(NULL, pkt);
921         ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
922
923         eh = (struct ether_header *) pktdata;
924
925         if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
926                 uint16 vlan_tag;
927                 int vlan_prio, dscp_prio = 0;
928
929                 evh = (struct ethervlan_header *)eh;
930
931                 vlan_tag = ntoh16(evh->vlan_tag);
932                 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
933
934                 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
935                         uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
936                         uint8 tos_tc = IP_TOS(ip_body);
937                         dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
938                 }
939
940                 /* DSCP priority gets precedence over 802.1P (vlan tag) */
941                 if (dscp_prio != 0) {
942                         priority = dscp_prio;
943                         rc |= PKTPRIO_VDSCP;
944                 } else {
945                         priority = vlan_prio;
946                         rc |= PKTPRIO_VLAN;
947                 }
948                 /* 
949                  * If the DSCP priority is not the same as the VLAN priority,
950                  * then overwrite the priority field in the vlan tag, with the
951                  * DSCP priority value. This is required for Linux APs because
952                  * the VLAN driver on Linux, overwrites the skb->priority field
953                  * with the priority value in the vlan tag
954                  */
955                 if (update_vtag && (priority != vlan_prio)) {
956                         vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
957                         vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
958                         evh->vlan_tag = hton16(vlan_tag);
959                         rc |= PKTPRIO_UPD;
960                 }
961         } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
962                 uint8 *ip_body = pktdata + sizeof(struct ether_header);
963                 uint8 tos_tc = IP_TOS(ip_body);
964                 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
965                 rc |= PKTPRIO_DSCP;
966         }
967
968         ASSERT(priority >= 0 && priority <= MAXPRIO);
969         PKTSETPRIO(pkt, priority);
970         return (rc | priority);
971 }
972
973 static char bcm_undeferrstr[BCME_STRLEN];
974
975 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
976
977 /* Convert the Error codes into related Error strings  */
978 const char *
979 bcmerrorstr(int bcmerror)
980 {
981         int abs_bcmerror;
982
983         abs_bcmerror = ABS(bcmerror);
984
985         /* check if someone added a bcmerror code but forgot to add errorstring */
986         ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
987         if ((bcmerror > 0) || (abs_bcmerror > ABS(BCME_LAST))) {
988                 sprintf(bcm_undeferrstr, "undefined Error %d", bcmerror);
989                 return bcm_undeferrstr;
990         }
991
992         ASSERT((strlen(bcmerrorstrtable[abs_bcmerror])) < BCME_STRLEN);
993
994         return bcmerrorstrtable[abs_bcmerror];
995 }
996
997 static void
998 BCMINITFN(bcm_nvram_refresh)(char *flash)
999 {
1000         int i;
1001         int ret = 0;
1002
1003         ASSERT(flash);
1004
1005         /* default "empty" vars cache */
1006         bzero(flash, 2);
1007
1008         if ((ret = nvram_getall(flash, NVRAM_SPACE)))
1009                 return;
1010
1011         /* determine nvram length */
1012         for (i = 0; i < NVRAM_SPACE; i++) {
1013                 if (flash[i] == '\0' && flash[i+1] == '\0')
1014                         break;
1015         }
1016
1017         if (i > 1)
1018                 vars_len = i + 2;
1019         else
1020                 vars_len = 0;
1021 }
1022
1023 char *
1024 bcm_nvram_vars(uint *length)
1025 {
1026 #ifndef BCMNVRAMR
1027         /* cache may be stale if nvram is read/write */
1028         if (nvram_vars) {
1029                 ASSERT(!bcmreclaimed);
1030                 bcm_nvram_refresh(nvram_vars);
1031         }
1032 #endif
1033         if (length)
1034                 *length = vars_len;
1035         return nvram_vars;
1036 }
1037
1038 /* copy nvram vars into locally-allocated multi-string array */
1039 int
1040 BCMINITFN(bcm_nvram_cache)(void *sbh)
1041 {
1042         void *osh;
1043         int ret = 0;
1044         char *flash = NULL;
1045
1046         if (vars_len >= 0) {
1047 #ifndef BCMNVRAMR
1048                 bcm_nvram_refresh(nvram_vars);
1049 #endif
1050                 return 0;
1051         }
1052
1053         osh = sb_osh((sb_t *)sbh);
1054
1055         /* allocate memory and read in flash */
1056         if (!(flash = MALLOC(osh, NVRAM_SPACE))) {
1057                 ret = BCME_NOMEM;
1058                 goto exit;
1059         }
1060
1061         bcm_nvram_refresh(flash);
1062
1063 #ifdef BCMNVRAMR
1064         if (vars_len > 3) {
1065                 /* copy into a properly-sized buffer */
1066                 if (!(nvram_vars = MALLOC(osh, vars_len))) {
1067                         ret = BCME_NOMEM;
1068                 } else
1069                         bcopy(flash, nvram_vars, vars_len);
1070         }
1071         MFREE(osh, flash, NVRAM_SPACE);
1072 #else
1073         /* cache must be full size of nvram if read/write */
1074         nvram_vars = flash;
1075 #endif  /* BCMNVRAMR */
1076
1077 exit:
1078         return ret;
1079 }
1080
1081 #ifdef BCMDBG_PKT       /* pkt logging for debugging */
1082 /* Add a packet to the pktlist */
1083 void
1084 pktlist_add(pktlist_info_t *pktlist, void *pkt)
1085 {
1086         uint i;
1087         ASSERT(pktlist->count < PKTLIST_SIZE);
1088
1089         /* Verify the packet is not already part of the list */
1090         for (i = 0; i < pktlist->count; i++) {
1091                 if (pktlist->list[i] == pkt)
1092                         ASSERT(0);
1093         }
1094         pktlist->list[pktlist->count] = pkt;
1095         pktlist->count++;
1096         return;
1097 }
1098
1099 /* Remove a packet from the pktlist */
1100 void
1101 pktlist_remove(pktlist_info_t *pktlist, void *pkt)
1102 {
1103         uint i;
1104         uint num = pktlist->count;
1105
1106         /* find the index where pkt exists */
1107         for (i = 0; i < num; i++)
1108         {
1109                 /* check for the existence of pkt in the list */
1110                 if (pktlist->list[i] == pkt)
1111                 {
1112                         /* replace with the last element */
1113                         pktlist->list[i] = pktlist->list[num-1];
1114                         pktlist->count--;
1115                         return;
1116                 }
1117         }
1118         ASSERT(0);
1119 }
1120
1121 /* Dump the pktlist (and the contents of each packet if 'data'
1122  * is set). 'buf' should be large enough
1123  */
1124
1125 char *
1126 pktlist_dump(pktlist_info_t *pktlist, char *buf)
1127 {
1128         char *obuf;
1129         uint i;
1130
1131         obuf = buf;
1132
1133         buf += sprintf(buf, "Packet list dump:\n");
1134
1135         for (i = 0; i < (pktlist->count); i++) {
1136                 buf += sprintf(buf, "0x%p\t", pktlist->list[i]);
1137
1138 #ifdef NOTDEF     /* Remove this ifdef to print pkttag and pktdata */
1139                 if (PKTTAG(pktlist->list[i])) {
1140                         /* Print pkttag */
1141                         buf += sprintf(buf, "Pkttag(in hex): ");
1142                         buf += bcm_format_hex(buf, PKTTAG(pktlist->list[i]), OSL_PKTTAG_SZ);
1143                 }
1144                 buf += sprintf(buf, "Pktdata(in hex): ");
1145                 buf += bcm_format_hex(buf, PKTDATA(NULL, pktlist->list[i]),
1146                         PKTLEN(NULL, pktlist->list[i]));
1147 #endif /* NOTDEF */
1148
1149                 buf += sprintf(buf, "\n");
1150         }
1151         return obuf;
1152 }
1153 #endif  /* BCMDBG_PKT */
1154
1155 /* iovar table lookup */
1156 const bcm_iovar_t*
1157 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1158 {
1159         const bcm_iovar_t *vi;
1160         const char *lookup_name;
1161
1162         /* skip any ':' delimited option prefixes */
1163         lookup_name = strrchr(name, ':');
1164         if (lookup_name != NULL)
1165                 lookup_name++;
1166         else
1167                 lookup_name = name;
1168
1169         ASSERT(table);
1170
1171         for (vi = table; vi->name; vi++) {
1172                 if (!strcmp(vi->name, lookup_name))
1173                         return vi;
1174         }
1175         /* ran to end of table */
1176
1177         return NULL; /* var name not found */
1178 }
1179
1180 int
1181 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1182 {
1183         int bcmerror = 0;
1184
1185         /* length check on io buf */
1186         switch (vi->type) {
1187         case IOVT_BOOL:
1188         case IOVT_INT8:
1189         case IOVT_INT16:
1190         case IOVT_INT32:
1191         case IOVT_UINT8:
1192         case IOVT_UINT16:
1193         case IOVT_UINT32:
1194                 /* all integers are int32 sized args at the ioctl interface */
1195                 if (len < (int)sizeof(int)) {
1196                         bcmerror = BCME_BUFTOOSHORT;
1197                 }
1198                 break;
1199
1200         case IOVT_BUFFER:
1201                 /* buffer must meet minimum length requirement */
1202                 if (len < vi->minlen) {
1203                         bcmerror = BCME_BUFTOOSHORT;
1204                 }
1205                 break;
1206
1207         case IOVT_VOID:
1208                 if (!set) {
1209                         /* Cannot return nil... */
1210                         bcmerror = BCME_UNSUPPORTED;
1211                 } else if (len) {
1212                         /* Set is an action w/o parameters */
1213                         bcmerror = BCME_BUFTOOLONG;
1214                 }
1215                 break;
1216
1217         default:
1218                 /* unknown type for length check in iovar info */
1219                 ASSERT(0);
1220                 bcmerror = BCME_UNSUPPORTED;
1221         }
1222
1223         return bcmerror;
1224 }
1225
1226 #endif  /* BCMDRIVER */
1227
1228
1229 #ifndef BCMROMOFFLOAD
1230 /*******************************************************************************
1231  * crc8
1232  *
1233  * Computes a crc8 over the input data using the polynomial:
1234  *
1235  *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
1236  *
1237  * The caller provides the initial value (either CRC8_INIT_VALUE
1238  * or the previous returned value) to allow for processing of
1239  * discontiguous blocks of data.  When generating the CRC the
1240  * caller is responsible for complementing the final return value
1241  * and inserting it into the byte stream.  When checking, a final
1242  * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1243  *
1244  * Reference: Dallas Semiconductor Application Note 27
1245  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1246  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1247  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1248  *
1249  * ****************************************************************************
1250  */
1251
1252 static const uint8 crc8_table[256] = {
1253     0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1254     0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1255     0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1256     0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1257     0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1258     0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1259     0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1260     0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1261     0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1262     0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1263     0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1264     0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1265     0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1266     0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1267     0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1268     0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1269     0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1270     0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1271     0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1272     0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1273     0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1274     0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1275     0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1276     0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1277     0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1278     0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1279     0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1280     0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1281     0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1282     0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1283     0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1284     0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1285 };
1286
1287 #define CRC_INNER_LOOP(n, c, x) \
1288         (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1289
1290 uint8
1291 BCMROMFN(hndcrc8)(
1292         uint8 *pdata,   /* pointer to array of data to process */
1293         uint  nbytes,   /* number of input data bytes to process */
1294         uint8 crc       /* either CRC8_INIT_VALUE or previous return value */
1295 )
1296 {
1297         /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1298          * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1299          */
1300         while (nbytes-- > 0)
1301                 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1302
1303         return crc;
1304 }
1305
1306 /*******************************************************************************
1307  * crc16
1308  *
1309  * Computes a crc16 over the input data using the polynomial:
1310  *
1311  *       x^16 + x^12 +x^5 + 1
1312  *
1313  * The caller provides the initial value (either CRC16_INIT_VALUE
1314  * or the previous returned value) to allow for processing of
1315  * discontiguous blocks of data.  When generating the CRC the
1316  * caller is responsible for complementing the final return value
1317  * and inserting it into the byte stream.  When checking, a final
1318  * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1319  *
1320  * Reference: Dallas Semiconductor Application Note 27
1321  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1322  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1323  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1324  *
1325  * ****************************************************************************
1326  */
1327
1328 static const uint16 crc16_table[256] = {
1329     0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1330     0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1331     0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1332     0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1333     0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1334     0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1335     0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1336     0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1337     0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1338     0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1339     0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1340     0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1341     0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1342     0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1343     0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1344     0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1345     0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1346     0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1347     0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1348     0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1349     0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1350     0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1351     0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1352     0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1353     0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1354     0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1355     0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1356     0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1357     0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1358     0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1359     0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1360     0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1361 };
1362
1363 uint16
1364 BCMROMFN(hndcrc16)(
1365     uint8 *pdata,  /* pointer to array of data to process */
1366     uint nbytes, /* number of input data bytes to process */
1367     uint16 crc     /* either CRC16_INIT_VALUE or previous return value */
1368 )
1369 {
1370         while (nbytes-- > 0)
1371                 CRC_INNER_LOOP(16, crc, *pdata++);
1372         return crc;
1373 }
1374
1375 static const uint32 crc32_table[256] = {
1376     0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1377     0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1378     0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1379     0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1380     0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1381     0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1382     0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1383     0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1384     0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1385     0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1386     0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1387     0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1388     0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1389     0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1390     0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1391     0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1392     0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1393     0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1394     0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1395     0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1396     0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1397     0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1398     0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1399     0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1400     0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1401     0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1402     0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1403     0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1404     0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1405     0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1406     0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1407     0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1408     0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1409     0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1410     0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1411     0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1412     0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1413     0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1414     0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1415     0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1416     0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1417     0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1418     0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1419     0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1420     0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1421     0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1422     0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1423     0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1424     0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1425     0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1426     0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1427     0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1428     0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1429     0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1430     0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1431     0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1432     0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1433     0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1434     0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1435     0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1436     0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1437     0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1438     0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1439     0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1440 };
1441
1442 uint32
1443 BCMROMFN(hndcrc32)(
1444     uint8 *pdata,  /* pointer to array of data to process */
1445     uint   nbytes, /* number of input data bytes to process */
1446     uint32 crc     /* either CRC32_INIT_VALUE or previous return value */
1447 )
1448 {
1449         uint8 *pend;
1450 #ifdef __mips__
1451         uint8 tmp[4];
1452         ulong *tptr = (ulong *)tmp;
1453
1454         /* in case the beginning of the buffer isn't aligned */
1455         pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
1456         nbytes -= (pend - pdata);
1457         while (pdata < pend)
1458                 CRC_INNER_LOOP(32, crc, *pdata++);
1459
1460         /* handle bulk of data as 32-bit words */
1461         pend = pdata + (nbytes & 0xfffffffc);
1462         while (pdata < pend) {
1463                 *tptr = *(ulong *)pdata;
1464                 pdata += sizeof(ulong *);
1465                 CRC_INNER_LOOP(32, crc, tmp[0]);
1466                 CRC_INNER_LOOP(32, crc, tmp[1]);
1467                 CRC_INNER_LOOP(32, crc, tmp[2]);
1468                 CRC_INNER_LOOP(32, crc, tmp[3]);
1469         }
1470
1471         /* 1-3 bytes at end of buffer */
1472         pend = pdata + (nbytes & 0x03);
1473         while (pdata < pend)
1474                 CRC_INNER_LOOP(32, crc, *pdata++);
1475 #else
1476         pend = pdata + nbytes;
1477         while (pdata < pend)
1478                 CRC_INNER_LOOP(32, crc, *pdata++);
1479 #endif /* __mips__ */
1480
1481         return crc;
1482 }
1483
1484 #ifdef notdef
1485 #define CLEN    1499    /*  CRC Length */
1486 #define CBUFSIZ         (CLEN+4)
1487 #define CNBUFS          5 /* # of bufs */
1488
1489 void testcrc32(void)
1490 {
1491         uint j, k, l;
1492         uint8 *buf;
1493         uint len[CNBUFS];
1494         uint32 crcr;
1495         uint32 crc32tv[CNBUFS] =
1496                 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1497
1498         ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1499
1500         /* step through all possible alignments */
1501         for (l = 0; l <= 4; l++) {
1502                 for (j = 0; j < CNBUFS; j++) {
1503                         len[j] = CLEN;
1504                         for (k = 0; k < len[j]; k++)
1505                                 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1506                 }
1507
1508                 for (j = 0; j < CNBUFS; j++) {
1509                         crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1510                         ASSERT(crcr == crc32tv[j]);
1511                 }
1512         }
1513
1514         MFREE(buf, CBUFSIZ*CNBUFS);
1515         return;
1516 }
1517 #endif /* notdef */
1518
1519 /*
1520  * Advance from the current 1-byte tag/1-byte length/variable-length value
1521  * triple, to the next, returning a pointer to the next.
1522  * If the current or next TLV is invalid (does not fit in given buffer length),
1523  * NULL is returned.
1524  * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1525  * by the TLV paramter's length if it is valid.
1526  */
1527 bcm_tlv_t *
1528 BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen)
1529 {
1530         int len;
1531
1532         /* validate current elt */
1533         if (!bcm_valid_tlv(elt, *buflen))
1534                 return NULL;
1535
1536         /* advance to next elt */
1537         len = elt->len;
1538         elt = (bcm_tlv_t*)(elt->data + len);
1539         *buflen -= (2 + len);
1540
1541         /* validate next elt */
1542         if (!bcm_valid_tlv(elt, *buflen))
1543                 return NULL;
1544
1545         return elt;
1546 }
1547
1548 /*
1549  * Traverse a string of 1-byte tag/1-byte length/variable-length value
1550  * triples, returning a pointer to the substring whose first element
1551  * matches tag
1552  */
1553 bcm_tlv_t *
1554 BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key)
1555 {
1556         bcm_tlv_t *elt;
1557         int totlen;
1558
1559         elt = (bcm_tlv_t*)buf;
1560         totlen = buflen;
1561
1562         /* find tagged parameter */
1563         while (totlen >= 2) {
1564                 int len = elt->len;
1565
1566                 /* validate remaining totlen */
1567                 if ((elt->id == key) && (totlen >= (len + 2)))
1568                         return (elt);
1569
1570                 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1571                 totlen -= (len + 2);
1572         }
1573
1574         return NULL;
1575 }
1576
1577 /*
1578  * Traverse a string of 1-byte tag/1-byte length/variable-length value
1579  * triples, returning a pointer to the substring whose first element
1580  * matches tag.  Stop parsing when we see an element whose ID is greater
1581  * than the target key.
1582  */
1583 bcm_tlv_t *
1584 BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key)
1585 {
1586         bcm_tlv_t *elt;
1587         int totlen;
1588
1589         elt = (bcm_tlv_t*)buf;
1590         totlen = buflen;
1591
1592         /* find tagged parameter */
1593         while (totlen >= 2) {
1594                 uint id = elt->id;
1595                 int len = elt->len;
1596
1597                 /* Punt if we start seeing IDs > than target key */
1598                 if (id > key)
1599                         return (NULL);
1600
1601                 /* validate remaining totlen */
1602                 if ((id == key) && (totlen >= (len + 2)))
1603                         return (elt);
1604
1605                 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1606                 totlen -= (len + 2);
1607         }
1608         return NULL;
1609 }
1610 #endif  /* !BCMROMOFFLOAD */
1611
1612 #ifdef BCMDBG
1613 int
1614 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1615 {
1616         int i;
1617         char* p = buf;
1618         char hexstr[16];
1619         int slen = 0;
1620         uint32 bit;
1621         const char* name;
1622
1623         if (len < 2 || !buf)
1624                 return 0;
1625
1626         buf[0] = '\0';
1627         len -= 1;
1628
1629         for (i = 0; flags != 0; i++) {
1630                 bit = bd[i].bit;
1631                 name = bd[i].name;
1632                 if (bit == 0 && flags) {
1633                         /* print any unnamed bits */
1634                         sprintf(hexstr, "0x%X", flags);
1635                         name = hexstr;
1636                         flags = 0;      /* exit loop */
1637                 } else if ((flags & bit) == 0)
1638                         continue;
1639                 slen += strlen(name);
1640                 if (len < slen)
1641                         break;
1642                 if (p != buf) p += sprintf(p, " "); /* btwn flag space */
1643                 strcat(p, name);
1644                 p += strlen(name);
1645                 flags &= ~bit;
1646                 len -= slen;
1647                 slen = 1;       /* account for btwn flag space */
1648         }
1649
1650         /* indicate the str was too short */
1651         if (flags != 0) {
1652                 if (len == 0)
1653                         p--;    /* overwrite last char */
1654                 p += sprintf(p, ">");
1655         }
1656
1657         return (int)(p - buf);
1658 }
1659
1660 void
1661 deadbeef(void *p, uint len)
1662 {
1663         static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
1664
1665         while (len-- > 0) {
1666                 *(uint8*)p = meat[((uintptr)p) & 3];
1667                 p = (uint8*)p + 1;
1668         }
1669 }
1670
1671 /* pretty hex print a contiguous buffer */
1672 void
1673 prhex(const char *msg, uchar *buf, uint nbytes)
1674 {
1675         char line[128], *p;
1676         uint i;
1677
1678         if (msg && (msg[0] != '\0'))
1679                 printf("%s:\n", msg);
1680
1681         p = line;
1682         for (i = 0; i < nbytes; i++) {
1683                 if (i % 16 == 0) {
1684                         p += sprintf(p, "  %04d: ", i); /* line prefix */
1685                 }
1686                 p += sprintf(p, "%02x ", buf[i]);
1687                 if (i % 16 == 15) {
1688                         printf("%s\n", line);           /* flush line */
1689                         p = line;
1690                 }
1691         }
1692
1693         /* flush last partial line */
1694         if (p != line)
1695                 printf("%s\n", line);
1696 }
1697
1698 /* print bytes formatted as hex to a string. return the resulting string length */
1699 int
1700 bcm_format_hex(char *str, const void *bytes, int len)
1701 {
1702         int i;
1703         char *p = str;
1704         const uint8 *src = (const uint8*)bytes;
1705
1706         for (i = 0; i < len; i++) {
1707                 p += sprintf(p, "%02X", *src);
1708                 src++;
1709         }
1710         return (int)(p - str);
1711 }
1712
1713 #endif /* BCMDBG */
1714
1715 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1716
1717 /* dump large strings to console */
1718 void
1719 printfbig(char *buf)
1720 {
1721         uint len, max_len;
1722         char c;
1723
1724         len = strlen(buf);
1725
1726         max_len = BUFSIZE_TODUMP_ATONCE;
1727
1728         while (len > max_len) {
1729                 c = buf[max_len];
1730                 buf[max_len] = '\0';
1731                 printf("%s", buf);
1732                 buf[max_len] = c;
1733
1734                 buf += max_len;
1735                 len -= max_len;
1736         }
1737         /* print the remaining string */
1738         printf("%s\n", buf);
1739         return;
1740 }
1741 /* routine to dump fields in a fileddesc structure */
1742 uint
1743 bcmdumpfields(readreg_rtn read_rtn, void *arg0, void *arg1, struct fielddesc *fielddesc_array,
1744         char *buf, uint32 bufsize)
1745 {
1746         uint  filled_len;
1747         uint len;
1748         struct fielddesc *cur_ptr;
1749
1750         filled_len = 0;
1751         cur_ptr = fielddesc_array;
1752
1753         while (bufsize > (filled_len + 64)) {
1754                 if (cur_ptr->nameandfmt == NULL)
1755                         break;
1756                 len = sprintf(buf, cur_ptr->nameandfmt, read_rtn(arg0, arg1, cur_ptr->offset));
1757                 buf += len;
1758                 filled_len += len;
1759                 cur_ptr++;
1760         }
1761         return filled_len;
1762 }
1763
1764 uint
1765 bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1766 {
1767         uint len;
1768
1769         len = strlen(name) + 1;
1770
1771         if ((len + datalen) > buflen)
1772                 return 0;
1773
1774         strcpy(buf, name);
1775
1776         /* append data onto the end of the name string */
1777         memcpy(&buf[len], data, datalen);
1778         len += datalen;
1779
1780         return len;
1781 }
1782
1783 /* Quarter dBm units to mW
1784  * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1785  * Table is offset so the last entry is largest mW value that fits in
1786  * a uint16.
1787  */
1788
1789 #define QDBM_OFFSET 153         /* Offset for first entry */
1790 #define QDBM_TABLE_LEN 40       /* Table size */
1791
1792 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1793  * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1794  */
1795 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1796
1797 /* Largest mW value that will round down to the last table entry,
1798  * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1799  * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1800  */
1801 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1802
1803 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1804 /* qdBm:        +0      +1      +2      +3      +4      +5      +6      +7 */
1805 /* 153: */      6683,   7079,   7499,   7943,   8414,   8913,   9441,   10000,
1806 /* 161: */      10593,  11220,  11885,  12589,  13335,  14125,  14962,  15849,
1807 /* 169: */      16788,  17783,  18836,  19953,  21135,  22387,  23714,  25119,
1808 /* 177: */      26607,  28184,  29854,  31623,  33497,  35481,  37584,  39811,
1809 /* 185: */      42170,  44668,  47315,  50119,  53088,  56234,  59566,  63096
1810 };
1811
1812 uint16
1813 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm)
1814 {
1815         uint factor = 1;
1816         int idx = qdbm - QDBM_OFFSET;
1817
1818         if (idx > QDBM_TABLE_LEN) {
1819                 /* clamp to max uint16 mW value */
1820                 return 0xFFFF;
1821         }
1822
1823         /* scale the qdBm index up to the range of the table 0-40
1824          * where an offset of 40 qdBm equals a factor of 10 mW.
1825          */
1826         while (idx < 0) {
1827                 idx += 40;
1828                 factor *= 10;
1829         }
1830
1831         /* return the mW value scaled down to the correct factor of 10,
1832          * adding in factor/2 to get proper rounding.
1833          */
1834         return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
1835 }
1836
1837 uint8
1838 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw)
1839 {
1840         uint8 qdbm;
1841         int offset;
1842         uint mw_uint = mw;
1843         uint boundary;
1844
1845         /* handle boundary case */
1846         if (mw_uint <= 1)
1847                 return 0;
1848
1849         offset = QDBM_OFFSET;
1850
1851         /* move mw into the range of the table */
1852         while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1853                 mw_uint *= 10;
1854                 offset -= 40;
1855         }
1856
1857         for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
1858                 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
1859                                                     nqdBm_to_mW_map[qdbm])/2;
1860                 if (mw_uint < boundary) break;
1861         }
1862
1863         qdbm += (uint8)offset;
1864
1865         return (qdbm);
1866 }
1867
1868
1869 uint
1870 BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint length)
1871 {
1872         uint bitcount = 0, i;
1873         uint8 tmp;
1874         for (i = 0; i < length; i++) {
1875                 tmp = bitmap[i];
1876                 while (tmp) {
1877                         bitcount++;
1878                         tmp &= (tmp - 1);
1879                 }
1880         }
1881         return bitcount;
1882 }
1883
1884 #ifdef BCMDRIVER
1885
1886 /* Initialization of bcmstrbuf structure */
1887 void
1888 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1889 {
1890         b->origsize = b->size = size;
1891         b->origbuf = b->buf = buf;
1892 }
1893
1894 /* Buffer sprintf wrapper to guard against buffer overflow */
1895 int
1896 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1897 {
1898         va_list ap;
1899         int r;
1900
1901         va_start(ap, fmt);
1902         r = vsnprintf(b->buf, b->size, fmt, ap);
1903
1904         /* Non Ansi C99 compliant returns -1,
1905          * Ansi compliant return r >= b->size,
1906          * bcmstdlib returns 0, handle all
1907          */
1908         if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1909                 b->size = 0;
1910         } else {
1911                 b->size -= r;
1912                 b->buf += r;
1913         }
1914
1915         va_end(ap);
1916
1917         return r;
1918 }
1919 #endif /* BCMDRIVER */