Updates to Tomato RAF including NGINX && PHP
[tomato.git] / release / src / shared / bcmutils.c
blobe78ce72ceeae1d6dd68a2d40599c847b8d297ea9
1 /*
2 * Driver O/S-independent utility routines
4 * Copyright 2007, 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$
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(_WIN32) || defined(NDIS) || defined(__vxworks) || \
27 defined(_CFE_) || defined(EFI)
28 /* debatable */
29 #include <bcmstdlib.h>
30 #endif
31 #include <bcmendian.h>
32 #include <bcmdevs.h>
33 #include <proto/ethernet.h>
34 #include <proto/vlan.h>
35 #include <proto/bcmip.h>
36 #include <proto/bcmtcp.h>
37 #include <proto/802.1d.h>
39 #ifdef BCMPERFSTATS
40 #include <bcmperf.h>
41 #endif
43 #ifdef BCMDRIVER
44 /* nvram vars cache */
45 static char *nvram_vars = NULL;
46 static int vars_len = -1;
48 /* copy a pkt buffer chain into a buffer */
49 uint
50 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
52 uint n, ret = 0;
54 if (len < 0)
55 len = 4096; /* "infinite" */
57 /* skip 'offset' bytes */
58 for (; p && offset; p = PKTNEXT(osh, p)) {
59 if (offset < (uint)PKTLEN(osh, p))
60 break;
61 offset -= PKTLEN(osh, p);
64 if (!p)
65 return 0;
67 /* copy the data */
68 for (; p && len; p = PKTNEXT(osh, p)) {
69 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
70 bcopy(PKTDATA(osh, p) + offset, buf, n);
71 buf += n;
72 len -= n;
73 ret += n;
74 offset = 0;
77 return ret;
80 /* return total length of buffer chain */
81 uint
82 pkttotlen(osl_t *osh, void *p)
84 uint total;
86 total = 0;
87 for (; p; p = PKTNEXT(osh, p))
88 total += PKTLEN(osh, p);
89 return (total);
92 /* return the last buffer of chained pkt */
93 void *
94 pktlast(osl_t *osh, void *p)
96 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
99 return (p);
104 * osl multiple-precedence packet queue
105 * hi_prec is always >= the number of the highest non-empty precedence
107 void *
108 pktq_penq(struct pktq *pq, int prec, void *p)
110 struct pktq_prec *q;
112 ASSERT(prec >= 0 && prec < pq->num_prec);
113 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
115 ASSERT(!pktq_full(pq));
116 ASSERT(!pktq_pfull(pq, prec));
118 q = &pq->q[prec];
120 if (q->head)
121 PKTSETLINK(q->tail, p);
122 else
123 q->head = p;
125 q->tail = p;
126 q->len++;
128 pq->len++;
130 if (pq->hi_prec < prec)
131 pq->hi_prec = (uint8)prec;
133 return p;
136 void *
137 pktq_penq_head(struct pktq *pq, int prec, void *p)
139 struct pktq_prec *q;
141 ASSERT(prec >= 0 && prec < pq->num_prec);
142 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
144 ASSERT(!pktq_full(pq));
145 ASSERT(!pktq_pfull(pq, prec));
147 q = &pq->q[prec];
149 if (q->head == NULL)
150 q->tail = p;
152 PKTSETLINK(p, q->head);
153 q->head = p;
154 q->len++;
156 pq->len++;
158 if (pq->hi_prec < prec)
159 pq->hi_prec = (uint8)prec;
161 return p;
164 void *
165 pktq_pdeq(struct pktq *pq, int prec)
167 struct pktq_prec *q;
168 void *p;
170 ASSERT(prec >= 0 && prec < pq->num_prec);
172 q = &pq->q[prec];
174 if ((p = q->head) == NULL)
175 return NULL;
177 if ((q->head = PKTLINK(p)) == NULL)
178 q->tail = NULL;
180 q->len--;
182 pq->len--;
184 PKTSETLINK(p, NULL);
186 return p;
189 void *
190 pktq_pdeq_tail(struct pktq *pq, int prec)
192 struct pktq_prec *q;
193 void *p, *prev;
195 ASSERT(prec >= 0 && prec < pq->num_prec);
197 q = &pq->q[prec];
199 if ((p = q->head) == NULL)
200 return NULL;
202 for (prev = NULL; p != q->tail; p = PKTLINK(p))
203 prev = p;
205 if (prev)
206 PKTSETLINK(prev, NULL);
207 else
208 q->head = NULL;
210 q->tail = prev;
211 q->len--;
213 pq->len--;
215 return p;
218 void
219 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
221 struct pktq_prec *q;
222 void *p;
224 q = &pq->q[prec];
225 p = q->head;
226 while (p) {
227 q->head = PKTLINK(p);
228 PKTSETLINK(p, NULL);
229 PKTFREE(osh, p, dir);
230 q->len--;
231 pq->len--;
232 p = q->head;
234 ASSERT(q->len == 0);
235 q->tail = NULL;
238 bool
239 pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
241 struct pktq_prec *q;
242 void *p;
244 ASSERT(prec >= 0 && prec < pq->num_prec);
246 if (!pktbuf)
247 return FALSE;
249 q = &pq->q[prec];
251 if (q->head == pktbuf) {
252 if ((q->head = PKTLINK(pktbuf)) == NULL)
253 q->tail = NULL;
254 } else {
255 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
257 if (p == NULL)
258 return FALSE;
260 PKTSETLINK(p, PKTLINK(pktbuf));
261 if (q->tail == pktbuf)
262 q->tail = p;
265 q->len--;
266 pq->len--;
267 PKTSETLINK(pktbuf, NULL);
268 return TRUE;
271 void
272 pktq_init(struct pktq *pq, int num_prec, int max_len)
274 int prec;
276 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
278 /* pq is variable size; only zero out what's requested */
279 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
281 pq->num_prec = (uint16)num_prec;
283 pq->max = (uint16)max_len;
285 for (prec = 0; prec < num_prec; prec++)
286 pq->q[prec].max = pq->max;
290 pktq_setmax(struct pktq *pq, int max_len)
292 int prec;
294 if (!max_len)
295 return pq->max;
297 pq->max = (uint16)max_len;
298 for (prec = 0; prec < pq->num_prec; prec++)
299 pq->q[prec].max = pq->max;
301 return pq->max;
304 void *
305 pktq_deq(struct pktq *pq, int *prec_out)
307 struct pktq_prec *q;
308 void *p;
309 int prec;
311 if (pq->len == 0)
312 return NULL;
314 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
315 pq->hi_prec--;
317 q = &pq->q[prec];
319 if ((p = q->head) == NULL)
320 return NULL;
322 if ((q->head = PKTLINK(p)) == NULL)
323 q->tail = NULL;
325 q->len--;
327 pq->len--;
329 if (prec_out)
330 *prec_out = prec;
332 PKTSETLINK(p, NULL);
334 return p;
337 void *
338 pktq_deq_tail(struct pktq *pq, int *prec_out)
340 struct pktq_prec *q;
341 void *p, *prev;
342 int prec;
344 if (pq->len == 0)
345 return NULL;
347 for (prec = 0; prec < pq->hi_prec; prec++)
348 if (pq->q[prec].head)
349 break;
351 q = &pq->q[prec];
353 if ((p = q->head) == NULL)
354 return NULL;
356 for (prev = NULL; p != q->tail; p = PKTLINK(p))
357 prev = p;
359 if (prev)
360 PKTSETLINK(prev, NULL);
361 else
362 q->head = NULL;
364 q->tail = prev;
365 q->len--;
367 pq->len--;
369 if (prec_out)
370 *prec_out = prec;
372 PKTSETLINK(p, NULL);
374 return p;
377 void *
378 pktq_peek(struct pktq *pq, int *prec_out)
380 int prec;
382 if (pq->len == 0)
383 return NULL;
385 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
386 pq->hi_prec--;
388 if (prec_out)
389 *prec_out = prec;
391 return (pq->q[prec].head);
394 void *
395 pktq_peek_tail(struct pktq *pq, int *prec_out)
397 int prec;
399 if (pq->len == 0)
400 return NULL;
402 for (prec = 0; prec < pq->hi_prec; prec++)
403 if (pq->q[prec].head)
404 break;
406 if (prec_out)
407 *prec_out = prec;
409 return (pq->q[prec].tail);
412 void
413 pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
415 int prec;
416 for (prec = 0; prec < pq->num_prec; prec++)
417 pktq_pflush(osh, pq, prec, dir);
418 ASSERT(pq->len == 0);
421 /* Return sum of lengths of a specific set of precedences */
423 pktq_mlen(struct pktq *pq, uint prec_bmp)
425 int prec, len;
427 len = 0;
429 for (prec = 0; prec <= pq->hi_prec; prec++)
430 if (prec_bmp & (1 << prec))
431 len += pq->q[prec].len;
433 return len;
436 /* Priority dequeue from a specific set of precedences */
437 void *
438 pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
440 struct pktq_prec *q;
441 void *p;
442 int prec;
444 if (pq->len == 0)
445 return NULL;
447 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
448 pq->hi_prec--;
450 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
451 if (prec-- == 0)
452 return NULL;
454 q = &pq->q[prec];
456 if ((p = q->head) == NULL)
457 return NULL;
459 if ((q->head = PKTLINK(p)) == NULL)
460 q->tail = NULL;
462 q->len--;
464 if (prec_out)
465 *prec_out = prec;
467 pq->len--;
469 PKTSETLINK(p, NULL);
471 return p;
473 #endif /* BCMDRIVER */
475 #ifndef BCMROMOFFLOAD
477 const unsigned char bcm_ctype[] = {
478 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
479 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
480 _BCM_C, /* 8-15 */
481 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
482 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
483 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
484 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
485 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
486 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
487 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
488 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
489 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
490 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
491 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
492 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
493 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
494 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
495 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
496 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
497 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
499 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
500 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
501 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
502 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
503 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
504 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
505 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
506 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
507 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
508 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
509 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
510 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
513 ulong
514 BCMROMFN(bcm_strtoul)(char *cp, char **endp, uint base)
516 ulong result, value;
517 bool minus;
519 minus = FALSE;
521 while (bcm_isspace(*cp))
522 cp++;
524 if (cp[0] == '+')
525 cp++;
526 else if (cp[0] == '-') {
527 minus = TRUE;
528 cp++;
531 if (base == 0) {
532 if (cp[0] == '0') {
533 if ((cp[1] == 'x') || (cp[1] == 'X')) {
534 base = 16;
535 cp = &cp[2];
536 } else {
537 base = 8;
538 cp = &cp[1];
540 } else
541 base = 10;
542 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
543 cp = &cp[2];
546 result = 0;
548 while (bcm_isxdigit(*cp) &&
549 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
550 result = result*base + value;
551 cp++;
554 if (minus)
555 result = (ulong)(result * -1);
557 if (endp)
558 *endp = (char *)cp;
560 return (result);
564 BCMROMFN(bcm_atoi)(char *s)
566 return (int)bcm_strtoul(s, NULL, 10);
569 /* return pointer to location of substring 'needle' in 'haystack' */
570 char*
571 BCMROMFN(bcmstrstr)(char *haystack, char *needle)
573 int len, nlen;
574 int i;
576 if ((haystack == NULL) || (needle == NULL))
577 return (haystack);
579 nlen = strlen(needle);
580 len = strlen(haystack) - nlen + 1;
582 for (i = 0; i < len; i++)
583 if (memcmp(needle, &haystack[i], nlen) == 0)
584 return (&haystack[i]);
585 return (NULL);
588 char*
589 BCMROMFN(bcmstrcat)(char *dest, const char *src)
591 strcpy(&dest[strlen(dest)], src);
592 return (dest);
595 char*
596 BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size)
598 char *endp;
599 char *p;
601 p = dest + strlen(dest);
602 endp = p + size;
604 while (p != endp && (*p++ = *src++) != '\0')
607 return (dest);
610 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
612 BCMROMFN(bcm_ether_atoe)(char *p, struct ether_addr *ea)
614 int i = 0;
616 for (;;) {
617 ea->octet[i++] = (char) bcm_strtoul(p, &p, 16);
618 if (!*p++ || i == 6)
619 break;
622 return (i == 6);
624 #endif /* !BCMROMOFFLOAD */
626 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
627 /* registry routine buffer preparation utility functions:
628 * parameter order is like strncpy, but returns count
629 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
631 ulong
632 wchar2ascii(
633 char *abuf,
634 ushort *wbuf,
635 ushort wbuflen,
636 ulong abuflen
639 ulong copyct = 1;
640 ushort i;
642 if (abuflen == 0)
643 return 0;
645 /* wbuflen is in bytes */
646 wbuflen /= sizeof(ushort);
648 for (i = 0; i < wbuflen; ++i) {
649 if (--abuflen == 0)
650 break;
651 *abuf++ = (char) *wbuf++;
652 ++copyct;
654 *abuf = '\0';
656 return copyct;
658 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
660 char *
661 bcm_ether_ntoa(struct ether_addr *ea, char *buf)
663 snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
664 ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff,
665 ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff);
666 return (buf);
669 char *
670 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
672 snprintf(buf, 16, "%d.%d.%d.%d",
673 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
674 return (buf);
677 #ifdef BCMDRIVER
679 void
680 bcm_mdelay(uint ms)
682 uint i;
684 for (i = 0; i < ms; i++) {
685 OSL_DELAY(1000);
690 * Search the name=value vars for a specific one and return its value.
691 * Returns NULL if not found.
693 char *
694 getvar(char *vars, const char *name)
696 #ifdef _MINOSL_
697 return NULL;
698 #else
699 char *s;
700 int len;
702 if (!name)
703 return NULL;
705 len = strlen(name);
706 if (len == 0)
707 return NULL;
709 /* first look in vars[] */
710 for (s = vars; s && *s;) {
711 /* CSTYLED */
712 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
713 return (&s[len+1]);
715 while (*s++)
719 /* then query nvram */
720 return (nvram_get(name));
721 #endif /* _MINOSL_ */
725 * Search the vars for a specific one and return its value as
726 * an integer. Returns 0 if not found.
729 getintvar(char *vars, const char *name)
731 #ifdef _MINOSL_
732 return 0;
733 #else
734 char *val;
736 if ((val = getvar(vars, name)) == NULL)
737 return (0);
739 return (bcm_strtoul(val, NULL, 0));
740 #endif /* _MINOSL_ */
744 /* Search for token in comma separated token-string */
745 static int
746 findmatch(char *string, char *name)
748 uint len;
749 char *c;
751 len = strlen(name);
752 /* CSTYLED */
753 while ((c = strchr(string, ',')) != NULL) {
754 if (len == (uint)(c - string) && !strncmp(string, name, len))
755 return 1;
756 string = c + 1;
759 return (!strcmp(string, name));
762 /* Return gpio pin number assigned to the named pin
764 * Variable should be in format:
766 * gpio<N>=pin_name,pin_name
768 * This format allows multiple features to share the gpio with mutual
769 * understanding.
771 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
772 * and if def_pin is not used by others.
774 uint
775 getgpiopin(char *vars, char *pin_name, uint def_pin)
777 char name[] = "gpioXXXX";
778 char *val;
779 uint pin;
781 /* Go thru all possibilities till a match in pin name */
782 for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
783 snprintf(name, sizeof(name), "gpio%d", pin);
784 val = getvar(vars, name);
785 if (val && findmatch(val, pin_name))
786 return pin;
789 if (def_pin != GPIO_PIN_NOTDEFINED) {
790 /* make sure the default pin is not used by someone else */
791 snprintf(name, sizeof(name), "gpio%d", def_pin);
792 if (getvar(vars, name)) {
793 def_pin = GPIO_PIN_NOTDEFINED;
797 return def_pin;
800 #ifdef BCMPERFSTATS
802 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
803 static struct {
804 uint cycles;
805 char *fmt;
806 uint a1;
807 uint a2;
808 } logtab[LOGSIZE];
810 /* last entry logged */
811 static uint logi = 0;
812 /* next entry to read */
813 static uint readi = 0;
815 void
816 bcm_perf_enable()
818 BCMPERF_ENABLE_INSTRCOUNT();
819 BCMPERF_ENABLE_ICACHE_MISS();
820 BCMPERF_ENABLE_ICACHE_HIT();
823 void
824 bcmlog(char *fmt, uint a1, uint a2)
826 static uint last = 0;
827 uint cycles, i;
828 OSL_GETCYCLES(cycles);
830 i = logi;
832 logtab[i].cycles = cycles - last;
833 logtab[i].fmt = fmt;
834 logtab[i].a1 = a1;
835 logtab[i].a2 = a2;
837 logi = (i + 1) % LOGSIZE;
838 last = cycles;
842 void
843 bcmstats(char *fmt)
845 static uint last = 0;
846 static uint32 ic_miss = 0;
847 static uint32 instr_count = 0;
848 uint32 ic_miss_cur;
849 uint32 instr_count_cur;
850 uint cycles, i;
852 OSL_GETCYCLES(cycles);
853 BCMPERF_GETICACHE_MISS(ic_miss_cur);
854 BCMPERF_GETINSTRCOUNT(instr_count_cur);
856 i = logi;
858 logtab[i].cycles = cycles - last;
859 logtab[i].a1 = ic_miss_cur - ic_miss;
860 logtab[i].a2 = instr_count_cur - instr_count;
861 logtab[i].fmt = fmt;
863 logi = (i + 1) % LOGSIZE;
865 last = cycles;
866 instr_count = instr_count_cur;
867 ic_miss = ic_miss_cur;
871 void
872 bcmdumplog(char *buf, int size)
874 char *limit, *line;
875 int j = 0;
876 int num;
878 limit = buf + size - 80;
879 *buf = '\0';
881 num = logi - readi;
883 if (num < 0)
884 num += LOGSIZE;
886 /* print in chronological order */
888 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
889 if (logtab[readi].fmt == NULL)
890 continue;
891 line = buf;
892 buf += sprintf(buf, "%d\t", logtab[readi].cycles);
893 buf += sprintf(buf, logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
894 buf += sprintf(buf, "\n");
901 * Dump one log entry at a time.
902 * Return index of next entry or -1 when no more .
905 bcmdumplogent(char *buf, uint i)
907 bool hit;
910 * If buf is NULL, return the starting index,
911 * interpreting i as the indicator of last 'i' entries to dump.
913 if (buf == NULL) {
914 i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
915 return ((logi - i) % LOGSIZE);
918 *buf = '\0';
920 ASSERT(i < LOGSIZE);
922 if (i == logi)
923 return (-1);
925 hit = FALSE;
926 for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) {
927 if (logtab[i].fmt == NULL)
928 continue;
929 buf += sprintf(buf, "%d: %d\t", i, logtab[i].cycles);
930 buf += sprintf(buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
931 buf += sprintf(buf, "\n");
932 hit = TRUE;
935 return (i);
938 #endif /* BCMPERFSTATS */
941 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
942 * Also updates the inplace vlan tag if requested.
943 * For debugging, it returns an indication of what it did.
945 uint
946 pktsetprio(void *pkt, bool update_vtag)
948 struct ether_header *eh;
949 struct ethervlan_header *evh;
950 uint8 *pktdata;
951 int priority = 0;
952 int rc = 0;
954 pktdata = (uint8 *) PKTDATA(NULL, pkt);
955 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
957 eh = (struct ether_header *) pktdata;
959 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
960 uint16 vlan_tag;
961 int vlan_prio, dscp_prio = 0;
963 evh = (struct ethervlan_header *)eh;
965 vlan_tag = ntoh16(evh->vlan_tag);
966 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
968 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
969 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
970 uint8 tos_tc = IP_TOS(ip_body);
971 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
972 if ((IP_VER(ip_body) == IP_VER_4) && (IPV4_PROT(ip_body) == IP_PROT_TCP)) {
973 int ip_len;
974 int src_port;
975 bool src_port_exc;
976 uint8 *tcp_hdr;
978 ip_len = IPV4_PAYLOAD_LEN(ip_body);
979 tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD(ip_body);
980 src_port = TCP_SRC_PORT(tcp_hdr);
981 src_port_exc = (src_port == 10110) || (src_port == 10120) ||
982 (src_port == 10130) || (src_port == 10140);
984 if ((ip_len == 40) && src_port_exc && TCP_IS_ACK(tcp_hdr)) {
985 dscp_prio = 7;
990 /* DSCP priority gets precedence over 802.1P (vlan tag) */
991 if (dscp_prio != 0) {
992 priority = dscp_prio;
993 rc |= PKTPRIO_VDSCP;
994 } else {
995 priority = vlan_prio;
996 rc |= PKTPRIO_VLAN;
999 * If the DSCP priority is not the same as the VLAN priority,
1000 * then overwrite the priority field in the vlan tag, with the
1001 * DSCP priority value. This is required for Linux APs because
1002 * the VLAN driver on Linux, overwrites the skb->priority field
1003 * with the priority value in the vlan tag
1005 if (update_vtag && (priority != vlan_prio)) {
1006 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
1007 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
1008 evh->vlan_tag = hton16(vlan_tag);
1009 rc |= PKTPRIO_UPD;
1011 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
1012 uint8 *ip_body = pktdata + sizeof(struct ether_header);
1013 uint8 tos_tc = IP_TOS(ip_body);
1014 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
1015 rc |= PKTPRIO_DSCP;
1016 if ((IP_VER(ip_body) == IP_VER_4) && (IPV4_PROT(ip_body) == IP_PROT_TCP)) {
1017 int ip_len;
1018 int src_port;
1019 bool src_port_exc;
1020 uint8 *tcp_hdr;
1022 ip_len = IPV4_PAYLOAD_LEN(ip_body);
1023 tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD(ip_body);
1024 src_port = TCP_SRC_PORT(tcp_hdr);
1025 src_port_exc = (src_port == 10110) || (src_port == 10120) ||
1026 (src_port == 10130) || (src_port == 10140);
1028 if ((ip_len == 40) && src_port_exc && TCP_IS_ACK(tcp_hdr)) {
1029 priority = 7;
1034 ASSERT(priority >= 0 && priority <= MAXPRIO);
1035 PKTSETPRIO(pkt, priority);
1036 return (rc | priority);
1039 static char bcm_undeferrstr[BCME_STRLEN];
1041 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1043 /* Convert the error codes into related error strings */
1044 const char *
1045 bcmerrorstr(int bcmerror)
1047 /* check if someone added a bcmerror code but forgot to add errorstring */
1048 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
1050 if (bcmerror > 0 || bcmerror < BCME_LAST) {
1051 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d", bcmerror);
1052 return bcm_undeferrstr;
1055 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1057 return bcmerrorstrtable[-bcmerror];
1060 static void
1061 BCMINITFN(bcm_nvram_refresh)(char *flash)
1063 int i;
1064 int ret = 0;
1066 ASSERT(flash);
1068 /* default "empty" vars cache */
1069 bzero(flash, 2);
1071 if ((ret = nvram_getall(flash, NVRAM_SPACE)))
1072 return;
1074 /* determine nvram length */
1075 for (i = 0; i < NVRAM_SPACE; i++) {
1076 if (flash[i] == '\0' && flash[i+1] == '\0')
1077 break;
1080 if (i > 1)
1081 vars_len = i + 2;
1082 else
1083 vars_len = 0;
1086 char *
1087 bcm_nvram_vars(uint *length)
1089 #ifndef BCMNVRAMR
1090 /* cache may be stale if nvram is read/write */
1091 if (nvram_vars) {
1092 ASSERT(!bcmreclaimed);
1093 bcm_nvram_refresh(nvram_vars);
1095 #endif
1096 if (length)
1097 *length = vars_len;
1098 return nvram_vars;
1101 /* copy nvram vars into locally-allocated multi-string array */
1103 BCMINITFN(bcm_nvram_cache)(void *sbh)
1105 void *osh;
1106 int ret = 0;
1107 char *flash = NULL;
1109 if (vars_len >= 0) {
1110 #ifndef BCMNVRAMR
1111 bcm_nvram_refresh(nvram_vars);
1112 #endif
1113 return 0;
1116 osh = sb_osh((sb_t *)sbh);
1118 /* allocate memory and read in flash */
1119 if (!(flash = MALLOC(osh, NVRAM_SPACE))) {
1120 ret = BCME_NOMEM;
1121 goto exit;
1124 bcm_nvram_refresh(flash);
1126 #ifdef BCMNVRAMR
1127 if (vars_len > 3) {
1128 /* copy into a properly-sized buffer */
1129 if (!(nvram_vars = MALLOC(osh, vars_len))) {
1130 ret = BCME_NOMEM;
1131 } else
1132 bcopy(flash, nvram_vars, vars_len);
1134 MFREE(osh, flash, NVRAM_SPACE);
1135 #else
1136 /* cache must be full size of nvram if read/write */
1137 nvram_vars = flash;
1138 #endif /* BCMNVRAMR */
1140 exit:
1141 return ret;
1144 #ifdef BCMDBG_PKT /* pkt logging for debugging */
1145 /* Add a packet to the pktlist */
1146 void
1147 pktlist_add(pktlist_info_t *pktlist, void *pkt)
1149 uint i;
1150 ASSERT(pktlist->count < PKTLIST_SIZE);
1152 /* Verify the packet is not already part of the list */
1153 for (i = 0; i < pktlist->count; i++) {
1154 if (pktlist->list[i] == pkt)
1155 ASSERT(0);
1157 pktlist->list[pktlist->count] = pkt;
1158 pktlist->count++;
1159 return;
1162 /* Remove a packet from the pktlist */
1163 void
1164 pktlist_remove(pktlist_info_t *pktlist, void *pkt)
1166 uint i;
1167 uint num = pktlist->count;
1169 /* find the index where pkt exists */
1170 for (i = 0; i < num; i++)
1172 /* check for the existence of pkt in the list */
1173 if (pktlist->list[i] == pkt)
1175 /* replace with the last element */
1176 pktlist->list[i] = pktlist->list[num-1];
1177 pktlist->count--;
1178 return;
1181 ASSERT(0);
1184 /* Dump the pktlist (and the contents of each packet if 'data'
1185 * is set). 'buf' should be large enough
1188 char *
1189 pktlist_dump(pktlist_info_t *pktlist, char *buf)
1191 char *obuf;
1192 uint i;
1194 obuf = buf;
1196 buf += sprintf(buf, "Packet list dump:\n");
1198 for (i = 0; i < (pktlist->count); i++) {
1199 buf += sprintf(buf, "0x%p\t", pktlist->list[i]);
1201 #ifdef NOTDEF /* Remove this ifdef to print pkttag and pktdata */
1202 if (PKTTAG(pktlist->list[i])) {
1203 /* Print pkttag */
1204 buf += sprintf(buf, "Pkttag(in hex): ");
1205 buf += bcm_format_hex(buf, PKTTAG(pktlist->list[i]), OSL_PKTTAG_SZ);
1207 buf += sprintf(buf, "Pktdata(in hex): ");
1208 buf += bcm_format_hex(buf, PKTDATA(NULL, pktlist->list[i]),
1209 PKTLEN(NULL, pktlist->list[i]));
1210 #endif /* NOTDEF */
1212 buf += sprintf(buf, "\n");
1214 return obuf;
1216 #endif /* BCMDBG_PKT */
1218 /* iovar table lookup */
1219 const bcm_iovar_t*
1220 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1222 const bcm_iovar_t *vi;
1223 const char *lookup_name;
1225 /* skip any ':' delimited option prefixes */
1226 lookup_name = strrchr(name, ':');
1227 if (lookup_name != NULL)
1228 lookup_name++;
1229 else
1230 lookup_name = name;
1232 ASSERT(table);
1234 for (vi = table; vi->name; vi++) {
1235 if (!strcmp(vi->name, lookup_name))
1236 return vi;
1238 /* ran to end of table */
1240 return NULL; /* var name not found */
1244 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1246 int bcmerror = 0;
1248 /* length check on io buf */
1249 switch (vi->type) {
1250 case IOVT_BOOL:
1251 case IOVT_INT8:
1252 case IOVT_INT16:
1253 case IOVT_INT32:
1254 case IOVT_UINT8:
1255 case IOVT_UINT16:
1256 case IOVT_UINT32:
1257 /* all integers are int32 sized args at the ioctl interface */
1258 if (len < (int)sizeof(int)) {
1259 bcmerror = BCME_BUFTOOSHORT;
1261 break;
1263 case IOVT_BUFFER:
1264 /* buffer must meet minimum length requirement */
1265 if (len < vi->minlen) {
1266 bcmerror = BCME_BUFTOOSHORT;
1268 break;
1270 case IOVT_VOID:
1271 if (!set) {
1272 /* Cannot return nil... */
1273 bcmerror = BCME_UNSUPPORTED;
1274 } else if (len) {
1275 /* Set is an action w/o parameters */
1276 bcmerror = BCME_BUFTOOLONG;
1278 break;
1280 default:
1281 /* unknown type for length check in iovar info */
1282 ASSERT(0);
1283 bcmerror = BCME_UNSUPPORTED;
1286 return bcmerror;
1289 #endif /* BCMDRIVER */
1292 #ifndef BCMROMOFFLOAD
1293 /*******************************************************************************
1294 * crc8
1296 * Computes a crc8 over the input data using the polynomial:
1298 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1300 * The caller provides the initial value (either CRC8_INIT_VALUE
1301 * or the previous returned value) to allow for processing of
1302 * discontiguous blocks of data. When generating the CRC the
1303 * caller is responsible for complementing the final return value
1304 * and inserting it into the byte stream. When checking, a final
1305 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1307 * Reference: Dallas Semiconductor Application Note 27
1308 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1309 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1310 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1312 * ****************************************************************************
1315 static const uint8 crc8_table[256] = {
1316 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1317 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1318 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1319 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1320 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1321 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1322 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1323 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1324 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1325 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1326 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1327 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1328 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1329 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1330 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1331 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1332 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1333 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1334 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1335 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1336 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1337 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1338 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1339 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1340 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1341 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1342 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1343 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1344 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1345 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1346 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1347 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1350 #define CRC_INNER_LOOP(n, c, x) \
1351 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1353 uint8
1354 BCMROMFN(hndcrc8)(
1355 uint8 *pdata, /* pointer to array of data to process */
1356 uint nbytes, /* number of input data bytes to process */
1357 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1360 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1361 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1363 while (nbytes-- > 0)
1364 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1366 return crc;
1369 /*******************************************************************************
1370 * crc16
1372 * Computes a crc16 over the input data using the polynomial:
1374 * x^16 + x^12 +x^5 + 1
1376 * The caller provides the initial value (either CRC16_INIT_VALUE
1377 * or the previous returned value) to allow for processing of
1378 * discontiguous blocks of data. When generating the CRC the
1379 * caller is responsible for complementing the final return value
1380 * and inserting it into the byte stream. When checking, a final
1381 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1383 * Reference: Dallas Semiconductor Application Note 27
1384 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1385 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1386 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1388 * ****************************************************************************
1391 static const uint16 crc16_table[256] = {
1392 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1393 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1394 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1395 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1396 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1397 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1398 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1399 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1400 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1401 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1402 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1403 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1404 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1405 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1406 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1407 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1408 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1409 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1410 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1411 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1412 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1413 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1414 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1415 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1416 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1417 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1418 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1419 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1420 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1421 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1422 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1423 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1426 uint16
1427 BCMROMFN(hndcrc16)(
1428 uint8 *pdata, /* pointer to array of data to process */
1429 uint nbytes, /* number of input data bytes to process */
1430 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1433 while (nbytes-- > 0)
1434 CRC_INNER_LOOP(16, crc, *pdata++);
1435 return crc;
1438 static const uint32 crc32_table[256] = {
1439 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1440 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1441 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1442 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1443 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1444 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1445 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1446 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1447 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1448 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1449 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1450 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1451 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1452 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1453 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1454 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1455 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1456 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1457 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1458 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1459 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1460 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1461 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1462 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1463 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1464 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1465 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1466 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1467 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1468 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1469 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1470 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1471 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1472 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1473 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1474 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1475 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1476 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1477 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1478 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1479 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1480 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1481 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1482 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1483 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1484 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1485 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1486 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1487 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1488 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1489 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1490 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1491 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1492 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1493 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1494 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1495 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1496 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1497 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1498 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1499 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1500 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1501 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1502 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1505 uint32
1506 BCMROMFN(hndcrc32)(
1507 uint8 *pdata, /* pointer to array of data to process */
1508 uint nbytes, /* number of input data bytes to process */
1509 uint32 crc /* either CRC32_INIT_VALUE or previous return value */
1512 uint8 *pend;
1513 #ifdef __mips__
1514 uint8 tmp[4];
1515 ulong *tptr = (ulong *)tmp;
1517 /* in case the beginning of the buffer isn't aligned */
1518 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
1519 nbytes -= (pend - pdata);
1520 while (pdata < pend)
1521 CRC_INNER_LOOP(32, crc, *pdata++);
1523 /* handle bulk of data as 32-bit words */
1524 pend = pdata + (nbytes & 0xfffffffc);
1525 while (pdata < pend) {
1526 *tptr = *(ulong *)pdata;
1527 pdata += sizeof(ulong *);
1528 CRC_INNER_LOOP(32, crc, tmp[0]);
1529 CRC_INNER_LOOP(32, crc, tmp[1]);
1530 CRC_INNER_LOOP(32, crc, tmp[2]);
1531 CRC_INNER_LOOP(32, crc, tmp[3]);
1534 /* 1-3 bytes at end of buffer */
1535 pend = pdata + (nbytes & 0x03);
1536 while (pdata < pend)
1537 CRC_INNER_LOOP(32, crc, *pdata++);
1538 #else
1539 pend = pdata + nbytes;
1540 while (pdata < pend)
1541 CRC_INNER_LOOP(32, crc, *pdata++);
1542 #endif /* __mips__ */
1544 return crc;
1547 #ifdef notdef
1548 #define CLEN 1499 /* CRC Length */
1549 #define CBUFSIZ (CLEN+4)
1550 #define CNBUFS 5 /* # of bufs */
1552 void testcrc32(void)
1554 uint j, k, l;
1555 uint8 *buf;
1556 uint len[CNBUFS];
1557 uint32 crcr;
1558 uint32 crc32tv[CNBUFS] =
1559 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1561 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1563 /* step through all possible alignments */
1564 for (l = 0; l <= 4; l++) {
1565 for (j = 0; j < CNBUFS; j++) {
1566 len[j] = CLEN;
1567 for (k = 0; k < len[j]; k++)
1568 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1571 for (j = 0; j < CNBUFS; j++) {
1572 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1573 ASSERT(crcr == crc32tv[j]);
1577 MFREE(buf, CBUFSIZ*CNBUFS);
1578 return;
1580 #endif /* notdef */
1583 * Advance from the current 1-byte tag/1-byte length/variable-length value
1584 * triple, to the next, returning a pointer to the next.
1585 * If the current or next TLV is invalid (does not fit in given buffer length),
1586 * NULL is returned.
1587 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1588 * by the TLV parameter's length if it is valid.
1590 bcm_tlv_t *
1591 BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen)
1593 int len;
1595 /* validate current elt */
1596 if (!bcm_valid_tlv(elt, *buflen))
1597 return NULL;
1599 /* advance to next elt */
1600 len = elt->len;
1601 elt = (bcm_tlv_t*)(elt->data + len);
1602 *buflen -= (2 + len);
1604 /* validate next elt */
1605 if (!bcm_valid_tlv(elt, *buflen))
1606 return NULL;
1608 return elt;
1612 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1613 * triples, returning a pointer to the substring whose first element
1614 * matches tag
1616 bcm_tlv_t *
1617 BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key)
1619 bcm_tlv_t *elt;
1620 int totlen;
1622 elt = (bcm_tlv_t*)buf;
1623 totlen = buflen;
1625 /* find tagged parameter */
1626 while (totlen >= 2) {
1627 int len = elt->len;
1629 /* validate remaining totlen */
1630 if ((elt->id == key) && (totlen >= (len + 2)))
1631 return (elt);
1633 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1634 totlen -= (len + 2);
1637 return NULL;
1641 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1642 * triples, returning a pointer to the substring whose first element
1643 * matches tag. Stop parsing when we see an element whose ID is greater
1644 * than the target key.
1646 bcm_tlv_t *
1647 BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key)
1649 bcm_tlv_t *elt;
1650 int totlen;
1652 elt = (bcm_tlv_t*)buf;
1653 totlen = buflen;
1655 /* find tagged parameter */
1656 while (totlen >= 2) {
1657 uint id = elt->id;
1658 int len = elt->len;
1660 /* Punt if we start seeing IDs > than target key */
1661 if (id > key)
1662 return (NULL);
1664 /* validate remaining totlen */
1665 if ((id == key) && (totlen >= (len + 2)))
1666 return (elt);
1668 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1669 totlen -= (len + 2);
1671 return NULL;
1673 #endif /* !BCMROMOFFLOAD */
1676 /* Produce a human-readable string for boardrev */
1677 char *
1678 bcm_brev_str(uint16 brev, char *buf)
1680 if (brev < 0x100)
1681 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1682 else
1683 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1685 return (buf);
1688 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1690 /* dump large strings to console */
1691 void
1692 printfbig(char *buf)
1694 uint len, max_len;
1695 char c;
1697 len = strlen(buf);
1699 max_len = BUFSIZE_TODUMP_ATONCE;
1701 while (len > max_len) {
1702 c = buf[max_len];
1703 buf[max_len] = '\0';
1704 printf("%s", buf);
1705 buf[max_len] = c;
1707 buf += max_len;
1708 len -= max_len;
1710 /* print the remaining string */
1711 printf("%s\n", buf);
1712 return;
1715 /* routine to dump fields in a fileddesc structure */
1716 uint
1717 bcmdumpfields(readreg_rtn read_rtn, void *arg0, void *arg1, struct fielddesc *fielddesc_array,
1718 char *buf, uint32 bufsize)
1720 uint filled_len;
1721 int len;
1722 struct fielddesc *cur_ptr;
1724 filled_len = 0;
1725 cur_ptr = fielddesc_array;
1727 while (bufsize > 1) {
1728 if (cur_ptr->nameandfmt == NULL)
1729 break;
1730 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1731 read_rtn(arg0, arg1, cur_ptr->offset));
1732 /* check for snprintf overflow or error */
1733 if (len < 0 || (uint32)len >= bufsize)
1734 len = bufsize - 1;
1735 buf += len;
1736 bufsize -= len;
1737 filled_len += len;
1738 cur_ptr++;
1740 return filled_len;
1743 uint
1744 bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1746 uint len;
1748 len = strlen(name) + 1;
1750 if ((len + datalen) > buflen)
1751 return 0;
1753 strncpy(buf, name, buflen);
1755 /* append data onto the end of the name string */
1756 memcpy(&buf[len], data, datalen);
1757 len += datalen;
1759 return len;
1762 #ifndef BCMROMOFFLOAD
1764 /* Quarter dBm units to mW
1765 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1766 * Table is offset so the last entry is largest mW value that fits in
1767 * a uint16.
1770 #define QDBM_OFFSET 153 /* Offset for first entry */
1771 #define QDBM_TABLE_LEN 40 /* Table size */
1773 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1774 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1776 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1778 /* Largest mW value that will round down to the last table entry,
1779 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1780 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1782 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1784 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1785 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1786 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1787 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1788 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1789 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1790 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1793 uint16
1794 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm)
1796 uint factor = 1;
1797 int idx = qdbm - QDBM_OFFSET;
1799 if (idx > QDBM_TABLE_LEN) {
1800 /* clamp to max uint16 mW value */
1801 return 0xFFFF;
1804 /* scale the qdBm index up to the range of the table 0-40
1805 * where an offset of 40 qdBm equals a factor of 10 mW.
1807 while (idx < 0) {
1808 idx += 40;
1809 factor *= 10;
1812 /* return the mW value scaled down to the correct factor of 10,
1813 * adding in factor/2 to get proper rounding.
1815 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
1818 uint8
1819 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw)
1821 uint8 qdbm;
1822 int offset;
1823 uint mw_uint = mw;
1824 uint boundary;
1826 /* handle boundary case */
1827 if (mw_uint <= 1)
1828 return 0;
1830 offset = QDBM_OFFSET;
1832 /* move mw into the range of the table */
1833 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1834 mw_uint *= 10;
1835 offset -= 40;
1838 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
1839 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
1840 nqdBm_to_mW_map[qdbm])/2;
1841 if (mw_uint < boundary) break;
1844 qdbm += (uint8)offset;
1846 return (qdbm);
1850 uint
1851 BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint length)
1853 uint bitcount = 0, i;
1854 uint8 tmp;
1855 for (i = 0; i < length; i++) {
1856 tmp = bitmap[i];
1857 while (tmp) {
1858 bitcount++;
1859 tmp &= (tmp - 1);
1862 return bitcount;
1865 #endif /* !BCMROMOFFLOAD */
1867 #ifdef BCMDRIVER
1869 /* Initialization of bcmstrbuf structure */
1870 void
1871 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1873 b->origsize = b->size = size;
1874 b->origbuf = b->buf = buf;
1877 /* Buffer sprintf wrapper to guard against buffer overflow */
1879 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1881 va_list ap;
1882 int r;
1884 va_start(ap, fmt);
1885 r = vsnprintf(b->buf, b->size, fmt, ap);
1887 /* Non Ansi C99 compliant returns -1,
1888 * Ansi compliant return r >= b->size,
1889 * bcmstdlib returns 0, handle all
1891 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1892 b->size = 0;
1893 } else {
1894 b->size -= r;
1895 b->buf += r;
1898 va_end(ap);
1900 return r;
1902 #endif /* BCMDRIVER */