[MINI2440] Updated defconfig to add (optional) packages
[openwrt/mini2440.git] / package / broadcom-wl / src / driver / bcmutils.c
blob88337d60c70880908b0e4af709477cf545f87705
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 #include <osl.h>
19 #include <sbutils.h>
20 #include <bcmnvram.h>
21 #include <bcmendian.h>
22 #include <bcmdevs.h>
23 #include "proto/ethernet.h"
24 #include "proto/vlan.h"
25 #include "proto/bcmip.h"
26 #include "proto/bcmtcp.h"
27 #include "proto/802.1d.h"
29 #ifdef BCMPERFSTATS
30 #include <bcmperf.h>
31 #endif
33 #if 0
34 /* nvram vars cache */
35 static char *nvram_vars = NULL;
36 static int vars_len = -1;
37 #endif
39 /* copy a pkt buffer chain into a buffer */
40 uint
41 pktcopy (osl_t * osh, void *p, uint offset, int len, uchar * buf)
43 uint n, ret = 0;
45 if (len < 0)
46 len = 4096; /* "infinite" */
48 /* skip 'offset' bytes */
49 for (; p && offset; p = PKTNEXT (osh, p))
51 if (offset < (uint) PKTLEN (osh, p))
52 break;
53 offset -= PKTLEN (osh, p);
56 if (!p)
57 return 0;
59 /* copy the data */
60 for (; p && len; p = PKTNEXT (osh, p))
62 n = MIN ((uint) PKTLEN (osh, p) - offset, (uint) len);
63 bcopy (PKTDATA (osh, p) + offset, buf, n);
64 buf += n;
65 len -= n;
66 ret += n;
67 offset = 0;
70 return ret;
73 /* return total length of buffer chain */
74 uint
75 pkttotlen (osl_t * osh, void *p)
77 uint total;
79 total = 0;
80 for (; p; p = PKTNEXT (osh, p))
81 total += PKTLEN (osh, p);
82 return (total);
85 /* return the last buffer of chained pkt */
86 void *
87 pktlast (osl_t * osh, void *p)
89 for (; PKTNEXT (osh, p); p = PKTNEXT (osh, p))
92 return (p);
97 * osl multiple-precedence packet queue
98 * hi_prec is always >= the number of the highest non-empty precedence
100 void *
101 pktq_penq (struct pktq *pq, int prec, void *p)
103 struct pktq_prec *q;
105 ASSERT (prec >= 0 && prec < pq->num_prec);
106 ASSERT (PKTLINK (p) == NULL); /* queueing chains not allowed */
108 ASSERT (!pktq_full (pq));
109 ASSERT (!pktq_pfull (pq, prec));
111 q = &pq->q[prec];
113 if (q->head)
114 PKTSETLINK (q->tail, p);
115 else
116 q->head = p;
118 q->tail = p;
119 q->len++;
121 pq->len++;
123 if (pq->hi_prec < prec)
124 pq->hi_prec = (uint8) prec;
126 return p;
129 void *
130 pktq_penq_head (struct pktq *pq, int prec, void *p)
132 struct pktq_prec *q;
134 ASSERT (prec >= 0 && prec < pq->num_prec);
135 ASSERT (PKTLINK (p) == NULL); /* queueing chains not allowed */
137 ASSERT (!pktq_full (pq));
138 ASSERT (!pktq_pfull (pq, prec));
140 q = &pq->q[prec];
142 if (q->head == NULL)
143 q->tail = p;
145 PKTSETLINK (p, q->head);
146 q->head = p;
147 q->len++;
149 pq->len++;
151 if (pq->hi_prec < prec)
152 pq->hi_prec = (uint8) prec;
154 return p;
157 void *
158 pktq_pdeq (struct pktq *pq, int prec)
160 struct pktq_prec *q;
161 void *p;
163 ASSERT (prec >= 0 && prec < pq->num_prec);
165 q = &pq->q[prec];
167 if ((p = q->head) == NULL)
168 return NULL;
170 if ((q->head = PKTLINK (p)) == NULL)
171 q->tail = NULL;
173 q->len--;
175 pq->len--;
177 PKTSETLINK (p, NULL);
179 return p;
182 void *
183 pktq_pdeq_tail (struct pktq *pq, int prec)
185 struct pktq_prec *q;
186 void *p, *prev;
188 ASSERT (prec >= 0 && prec < pq->num_prec);
190 q = &pq->q[prec];
192 if ((p = q->head) == NULL)
193 return NULL;
195 for (prev = NULL; p != q->tail; p = PKTLINK (p))
196 prev = p;
198 if (prev)
199 PKTSETLINK (prev, NULL);
200 else
201 q->head = NULL;
203 q->tail = prev;
204 q->len--;
206 pq->len--;
208 return p;
211 void
212 pktq_pflush (osl_t * osh, struct pktq *pq, int prec, bool dir)
214 struct pktq_prec *q;
215 void *p;
217 q = &pq->q[prec];
218 p = q->head;
219 while (p)
221 q->head = PKTLINK (p);
222 PKTSETLINK (p, NULL);
223 PKTFREE (osh, p, dir);
224 q->len--;
225 pq->len--;
226 p = q->head;
228 ASSERT (q->len == 0);
229 q->tail = NULL;
232 #if 0
233 bool
234 pktq_pdel (struct pktq *pq, void *pktbuf, int prec)
236 struct pktq_prec *q;
237 void *p;
239 ASSERT (prec >= 0 && prec < pq->num_prec);
241 if (!pktbuf)
242 return FALSE;
244 q = &pq->q[prec];
246 if (q->head == pktbuf)
248 if ((q->head = PKTLINK (pktbuf)) == NULL)
249 q->tail = NULL;
251 else
253 for (p = q->head; p && PKTLINK (p) != pktbuf; p = PKTLINK (p))
255 if (p == NULL)
256 return FALSE;
258 PKTSETLINK (p, PKTLINK (pktbuf));
259 if (q->tail == pktbuf)
260 q->tail = p;
263 q->len--;
264 pq->len--;
265 PKTSETLINK (pktbuf, NULL);
266 return TRUE;
268 #endif
270 void
271 pktq_init (struct pktq *pq, int num_prec, int max_len)
273 int prec;
275 ASSERT (num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
277 /* pq is variable size; only zero out what's requested */
278 bzero (pq,
279 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 #if 0
378 void *
379 pktq_peek (struct pktq *pq, int *prec_out)
381 int prec;
383 if (pq->len == 0)
384 return NULL;
386 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
387 pq->hi_prec--;
389 if (prec_out)
390 *prec_out = prec;
392 return (pq->q[prec].head);
394 #endif
396 void *
397 pktq_peek_tail (struct pktq *pq, int *prec_out)
399 int prec;
401 if (pq->len == 0)
402 return NULL;
404 for (prec = 0; prec < pq->hi_prec; prec++)
405 if (pq->q[prec].head)
406 break;
408 if (prec_out)
409 *prec_out = prec;
411 return (pq->q[prec].tail);
414 void
415 pktq_flush (osl_t * osh, struct pktq *pq, bool dir)
417 int prec;
418 for (prec = 0; prec < pq->num_prec; prec++)
419 pktq_pflush (osh, pq, prec, dir);
420 ASSERT (pq->len == 0);
423 /* Return sum of lengths of a specific set of precedences */
425 pktq_mlen (struct pktq *pq, uint prec_bmp)
427 int prec, len;
429 len = 0;
431 for (prec = 0; prec <= pq->hi_prec; prec++)
432 if (prec_bmp & (1 << prec))
433 len += pq->q[prec].len;
435 return len;
438 /* Priority dequeue from a specific set of precedences */
439 void *
440 pktq_mdeq (struct pktq *pq, uint prec_bmp, int *prec_out)
442 struct pktq_prec *q;
443 void *p;
444 int prec;
446 if (pq->len == 0)
447 return NULL;
449 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
450 pq->hi_prec--;
452 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
453 if (prec-- == 0)
454 return NULL;
456 q = &pq->q[prec];
458 if ((p = q->head) == NULL)
459 return NULL;
461 if ((q->head = PKTLINK (p)) == NULL)
462 q->tail = NULL;
464 q->len--;
466 if (prec_out)
467 *prec_out = prec;
469 pq->len--;
471 PKTSETLINK (p, NULL);
473 return p;
476 const unsigned char bcm_ctype[] = {
477 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, /* 0-7 */
478 _BCM_C, _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C | _BCM_S,
479 _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,
488 _BCM_U | _BCM_X,
489 _BCM_U | _BCM_X, _BCM_U, /* 64-71 */
490 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 72-79 */
491 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 80-87 */
492 _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 88-95 */
493 _BCM_P, _BCM_L | _BCM_X, _BCM_L | _BCM_X, _BCM_L | _BCM_X, _BCM_L | _BCM_X,
494 _BCM_L | _BCM_X,
495 _BCM_L | _BCM_X, _BCM_L, /* 96-103 */
496 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 104-111 */
497 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 112-119 */
498 _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_C, /* 120-127 */
499 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
500 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
501 _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
502 _BCM_P, _BCM_P,
503 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
504 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
505 _BCM_P, _BCM_P,
506 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
507 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
508 _BCM_U, _BCM_U,
509 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
510 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U,
511 _BCM_U, _BCM_U,
512 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
513 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
514 _BCM_L, _BCM_L,
515 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
516 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L,
517 _BCM_L, _BCM_L,
518 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
521 ulong BCMROMFN (bcm_strtoul) (char *cp, char **endp, uint base)
523 ulong result, value;
524 bool minus;
526 minus = FALSE;
528 while (bcm_isspace (*cp))
529 cp++;
531 if (cp[0] == '+')
532 cp++;
533 else if (cp[0] == '-')
535 minus = TRUE;
536 cp++;
539 if (base == 0)
541 if (cp[0] == '0')
543 if ((cp[1] == 'x') || (cp[1] == 'X'))
545 base = 16;
546 cp = &cp[2];
548 else
550 base = 8;
551 cp = &cp[1];
554 else
555 base = 10;
557 else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X')))
559 cp = &cp[2];
562 result = 0;
564 while (bcm_isxdigit (*cp) &&
565 (value =
566 bcm_isdigit (*cp) ? *cp - '0' : bcm_toupper (*cp) - 'A' + 10) <
567 base)
569 result = result * base + value;
570 cp++;
573 if (minus)
574 result = (ulong) (result * -1);
576 if (endp)
577 *endp = (char *) cp;
579 return (result);
582 #if 0
583 int BCMROMFN (bcm_atoi) (char *s)
585 return (int) bcm_strtoul (s, NULL, 10);
588 /* return pointer to location of substring 'needle' in 'haystack' */
589 char *BCMROMFN (bcmstrstr) (char *haystack, char *needle)
591 int len, nlen;
592 int i;
594 if ((haystack == NULL) || (needle == NULL))
595 return (haystack);
597 nlen = strlen (needle);
598 len = strlen (haystack) - nlen + 1;
600 for (i = 0; i < len; i++)
601 if (memcmp (needle, &haystack[i], nlen) == 0)
602 return (&haystack[i]);
603 return (NULL);
606 char *BCMROMFN (bcmstrcat) (char *dest, const char *src)
608 strcpy (&dest[strlen (dest)], src);
609 return (dest);
612 char *BCMROMFN (bcmstrncat) (char *dest, const char *src, uint size)
614 char *endp;
615 char *p;
617 p = dest + strlen (dest);
618 endp = p + size;
620 while (p != endp && (*p++ = *src++) != '\0')
623 return (dest);
625 #endif
627 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
628 int BCMROMFN (bcm_ether_atoe) (char *p, struct ether_addr * ea)
630 int i = 0;
632 for (;;)
634 ea->octet[i++] = (char) bcm_strtoul (p, &p, 16);
635 if (!*p++ || i == 6)
636 break;
639 return (i == 6);
642 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
643 /* registry routine buffer preparation utility functions:
644 * parameter order is like strncpy, but returns count
645 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
647 ulong
648 wchar2ascii (char *abuf, ushort * wbuf, ushort wbuflen, ulong abuflen)
650 ulong copyct = 1;
651 ushort i;
653 if (abuflen == 0)
654 return 0;
656 /* wbuflen is in bytes */
657 wbuflen /= sizeof (ushort);
659 for (i = 0; i < wbuflen; ++i)
661 if (--abuflen == 0)
662 break;
663 *abuf++ = (char) *wbuf++;
664 ++copyct;
666 *abuf = '\0';
668 return copyct;
670 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
672 #if 0
673 char *
674 bcm_ether_ntoa (struct ether_addr *ea, char *buf)
676 snprintf (buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
677 ea->octet[0] & 0xff, ea->octet[1] & 0xff, ea->octet[2] & 0xff,
678 ea->octet[3] & 0xff, ea->octet[4] & 0xff, ea->octet[5] & 0xff);
679 return (buf);
682 char *
683 bcm_ip_ntoa (struct ipv4_addr *ia, char *buf)
685 snprintf (buf, 16, "%d.%d.%d.%d",
686 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
687 return (buf);
689 void
690 bcm_mdelay (uint ms)
692 uint i;
694 for (i = 0; i < ms; i++)
696 OSL_DELAY (1000);
699 #endif
701 #if 0
704 * Search the name=value vars for a specific one and return its value.
705 * Returns NULL if not found.
707 char *
708 getvar (char *vars, const char *name)
710 #ifdef _MINOSL_
711 return NULL;
712 #else
713 char *s;
714 int len;
716 if (!name)
717 return NULL;
719 len = strlen (name);
720 if (len == 0)
721 return NULL;
723 /* first look in vars[] */
724 for (s = vars; s && *s;)
726 /* CSTYLED */
727 if ((bcmp (s, name, len) == 0) && (s[len] == '='))
728 return (&s[len + 1]);
730 while (*s++)
734 /* then query nvram */
735 return (nvram_get (name));
736 #endif /* _MINOSL_ */
740 * Search the vars for a specific one and return its value as
741 * an integer. Returns 0 if not found.
744 getintvar (char *vars, const char *name)
746 #ifdef _MINOSL_
747 return 0;
748 #else
749 char *val;
751 if ((val = getvar (vars, name)) == NULL)
752 return (0);
754 return (bcm_strtoul (val, NULL, 0));
755 #endif /* _MINOSL_ */
759 /* Search for token in comma separated token-string */
760 static int
761 findmatch (char *string, char *name)
763 uint len;
764 char *c;
766 len = strlen (name);
767 /* CSTYLED */
768 while ((c = strchr (string, ',')) != NULL)
770 if (len == (uint) (c - string) && !strncmp (string, name, len))
771 return 1;
772 string = c + 1;
775 return (!strcmp (string, name));
778 /* Return gpio pin number assigned to the named pin
780 * Variable should be in format:
782 * gpio<N>=pin_name,pin_name
784 * This format allows multiple features to share the gpio with mutual
785 * understanding.
787 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
788 * and if def_pin is not used by others.
790 uint
791 getgpiopin (char *vars, char *pin_name, uint def_pin)
793 char name[] = "gpioXXXX";
794 char *val;
795 uint pin;
797 /* Go thru all possibilities till a match in pin name */
798 for (pin = 0; pin < GPIO_NUMPINS; pin++)
800 snprintf (name, sizeof (name), "gpio%d", pin);
801 val = getvar (vars, name);
802 if (val && findmatch (val, pin_name))
803 return pin;
806 if (def_pin != GPIO_PIN_NOTDEFINED)
808 /* make sure the default pin is not used by someone else */
809 snprintf (name, sizeof (name), "gpio%d", def_pin);
810 if (getvar (vars, name))
812 def_pin = GPIO_PIN_NOTDEFINED;
816 return def_pin;
818 #endif
820 #ifdef BCMPERFSTATS
822 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
823 static struct
825 uint cycles;
826 char *fmt;
827 uint a1;
828 uint a2;
829 } logtab[LOGSIZE];
831 /* last entry logged */
832 static uint logi = 0;
833 /* next entry to read */
834 static uint readi = 0;
836 void
837 bcm_perf_enable ()
839 BCMPERF_ENABLE_INSTRCOUNT ();
840 BCMPERF_ENABLE_ICACHE_MISS ();
841 BCMPERF_ENABLE_ICACHE_HIT ();
844 void
845 bcmlog (char *fmt, uint a1, uint a2)
847 static uint last = 0;
848 uint cycles, i;
849 OSL_GETCYCLES (cycles);
851 i = logi;
853 logtab[i].cycles = cycles - last;
854 logtab[i].fmt = fmt;
855 logtab[i].a1 = a1;
856 logtab[i].a2 = a2;
858 logi = (i + 1) % LOGSIZE;
859 last = cycles;
863 void
864 bcmstats (char *fmt)
866 static uint last = 0;
867 static uint32 ic_miss = 0;
868 static uint32 instr_count = 0;
869 uint32 ic_miss_cur;
870 uint32 instr_count_cur;
871 uint cycles, i;
873 OSL_GETCYCLES (cycles);
874 BCMPERF_GETICACHE_MISS (ic_miss_cur);
875 BCMPERF_GETINSTRCOUNT (instr_count_cur);
877 i = logi;
879 logtab[i].cycles = cycles - last;
880 logtab[i].a1 = ic_miss_cur - ic_miss;
881 logtab[i].a2 = instr_count_cur - instr_count;
882 logtab[i].fmt = fmt;
884 logi = (i + 1) % LOGSIZE;
886 last = cycles;
887 instr_count = instr_count_cur;
888 ic_miss = ic_miss_cur;
892 void
893 bcmdumplog (char *buf, int size)
895 char *limit, *line;
896 int j = 0;
897 int num;
899 limit = buf + size - 80;
900 *buf = '\0';
902 num = logi - readi;
904 if (num < 0)
905 num += LOGSIZE;
907 /* print in chronological order */
909 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++)
911 if (logtab[readi].fmt == NULL)
912 continue;
913 line = buf;
914 buf += sprintf (buf, "%d\t", logtab[readi].cycles);
915 buf +=
916 sprintf (buf, logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
917 buf += sprintf (buf, "\n");
924 * Dump one log entry at a time.
925 * Return index of next entry or -1 when no more .
928 bcmdumplogent (char *buf, uint i)
930 bool hit;
933 * If buf is NULL, return the starting index,
934 * interpreting i as the indicator of last 'i' entries to dump.
936 if (buf == NULL)
938 i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
939 return ((logi - i) % LOGSIZE);
942 *buf = '\0';
944 ASSERT (i < LOGSIZE);
946 if (i == logi)
947 return (-1);
949 hit = FALSE;
950 for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE)
952 if (logtab[i].fmt == NULL)
953 continue;
954 buf += sprintf (buf, "%d: %d\t", i, logtab[i].cycles);
955 buf += sprintf (buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
956 buf += sprintf (buf, "\n");
957 hit = TRUE;
960 return (i);
963 #endif /* BCMPERFSTATS */
965 #ifdef BCMDBG
966 /* pretty hex print a pkt buffer chain */
967 void
968 prpkt (const char *msg, osl_t * osh, void *p0)
970 void *p;
972 if (msg && (msg[0] != '\0'))
973 printf ("%s:\n", msg);
975 for (p = p0; p; p = PKTNEXT (osh, p))
976 prhex (NULL, PKTDATA (osh, p), PKTLEN (osh, p));
978 #endif /* BCMDBG */
980 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
981 * Also updates the inplace vlan tag if requested.
982 * For debugging, it returns an indication of what it did.
984 uint
985 pktsetprio (void *pkt, bool update_vtag)
987 struct ether_header *eh;
988 struct ethervlan_header *evh;
989 uint8 *pktdata;
990 int priority = 0;
991 int rc = 0;
993 pktdata = (uint8 *) PKTDATA (NULL, pkt);
994 ASSERT (ISALIGNED ((uintptr) pktdata, sizeof (uint16)));
996 eh = (struct ether_header *) pktdata;
998 if (ntoh16 (eh->ether_type) == ETHER_TYPE_8021Q)
1000 uint16 vlan_tag;
1001 int vlan_prio, dscp_prio = 0;
1003 evh = (struct ethervlan_header *) eh;
1005 vlan_tag = ntoh16 (evh->vlan_tag);
1006 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
1008 if (ntoh16 (evh->ether_type) == ETHER_TYPE_IP)
1010 uint8 *ip_body = pktdata + sizeof (struct ethervlan_header);
1011 uint8 tos_tc = IP_TOS (ip_body);
1012 dscp_prio = (int) (tos_tc >> IPV4_TOS_PREC_SHIFT);
1013 if ((IP_VER (ip_body) == IP_VER_4)
1014 && (IPV4_PROT (ip_body) == IP_PROT_TCP))
1016 int ip_len;
1017 int src_port;
1018 bool src_port_exc;
1019 uint8 *tcp_hdr;
1021 ip_len = IPV4_PAYLOAD_LEN (ip_body);
1022 tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD (ip_body);
1023 src_port = TCP_SRC_PORT (tcp_hdr);
1024 src_port_exc = (src_port == 10110) || (src_port == 10120) ||
1025 (src_port == 10130) || (src_port == 10140);
1027 if ((ip_len == 40) && src_port_exc && TCP_IS_ACK (tcp_hdr))
1029 dscp_prio = 7;
1034 /* DSCP priority gets precedence over 802.1P (vlan tag) */
1035 if (dscp_prio != 0)
1037 priority = dscp_prio;
1038 rc |= PKTPRIO_VDSCP;
1040 else
1042 priority = vlan_prio;
1043 rc |= PKTPRIO_VLAN;
1046 * If the DSCP priority is not the same as the VLAN priority,
1047 * then overwrite the priority field in the vlan tag, with the
1048 * DSCP priority value. This is required for Linux APs because
1049 * the VLAN driver on Linux, overwrites the skb->priority field
1050 * with the priority value in the vlan tag
1052 if (update_vtag && (priority != vlan_prio))
1054 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
1055 vlan_tag |= (uint16) priority << VLAN_PRI_SHIFT;
1056 evh->vlan_tag = hton16 (vlan_tag);
1057 rc |= PKTPRIO_UPD;
1060 else if (ntoh16 (eh->ether_type) == ETHER_TYPE_IP)
1062 uint8 *ip_body = pktdata + sizeof (struct ether_header);
1063 uint8 tos_tc = IP_TOS (ip_body);
1064 priority = (int) (tos_tc >> IPV4_TOS_PREC_SHIFT);
1065 rc |= PKTPRIO_DSCP;
1066 if ((IP_VER (ip_body) == IP_VER_4)
1067 && (IPV4_PROT (ip_body) == IP_PROT_TCP))
1069 int ip_len;
1070 int src_port;
1071 bool src_port_exc;
1072 uint8 *tcp_hdr;
1074 ip_len = IPV4_PAYLOAD_LEN (ip_body);
1075 tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD (ip_body);
1076 src_port = TCP_SRC_PORT (tcp_hdr);
1077 src_port_exc = (src_port == 10110) || (src_port == 10120) ||
1078 (src_port == 10130) || (src_port == 10140);
1080 if ((ip_len == 40) && src_port_exc && TCP_IS_ACK (tcp_hdr))
1082 priority = 7;
1087 ASSERT (priority >= 0 && priority <= MAXPRIO);
1088 PKTSETPRIO (pkt, priority);
1089 return (rc | priority);
1092 static char bcm_undeferrstr[BCME_STRLEN];
1094 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1096 /* Convert the error codes into related error strings */
1097 const char *
1098 bcmerrorstr (int bcmerror)
1100 /* check if someone added a bcmerror code but forgot to add errorstring */
1101 ASSERT (ABS (BCME_LAST) == (ARRAYSIZE (bcmerrorstrtable) - 1));
1103 if (bcmerror > 0 || bcmerror < BCME_LAST)
1105 snprintf (bcm_undeferrstr, BCME_STRLEN, "Undefined error %d", bcmerror);
1106 return bcm_undeferrstr;
1109 ASSERT (strlen (bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1111 return bcmerrorstrtable[-bcmerror];
1114 #if 0
1115 static void BCMINITFN (bcm_nvram_refresh) (char *flash)
1117 int i;
1118 int ret = 0;
1120 ASSERT (flash);
1122 /* default "empty" vars cache */
1123 bzero (flash, 2);
1125 if ((ret = nvram_getall (flash, NVRAM_SPACE)))
1126 return;
1128 /* determine nvram length */
1129 for (i = 0; i < NVRAM_SPACE; i++)
1131 if (flash[i] == '\0' && flash[i + 1] == '\0')
1132 break;
1135 if (i > 1)
1136 vars_len = i + 2;
1137 else
1138 vars_len = 0;
1140 #endif
1142 #ifdef BCMDBG_PKT /* pkt logging for debugging */
1143 /* Add a packet to the pktlist */
1144 void
1145 pktlist_add (pktlist_info_t * pktlist, void *pkt)
1147 uint i;
1148 ASSERT (pktlist->count < PKTLIST_SIZE);
1150 /* Verify the packet is not already part of the list */
1151 for (i = 0; i < pktlist->count; i++)
1153 if (pktlist->list[i] == pkt)
1154 ASSERT (0);
1156 pktlist->list[pktlist->count] = pkt;
1157 pktlist->count++;
1158 return;
1161 /* Remove a packet from the pktlist */
1162 void
1163 pktlist_remove (pktlist_info_t * pktlist, void *pkt)
1165 uint i;
1166 uint num = pktlist->count;
1168 /* find the index where pkt exists */
1169 for (i = 0; i < num; i++)
1171 /* check for the existence of pkt in the list */
1172 if (pktlist->list[i] == pkt)
1174 /* replace with the last element */
1175 pktlist->list[i] = pktlist->list[num - 1];
1176 pktlist->count--;
1177 return;
1180 ASSERT (0);
1183 /* Dump the pktlist (and the contents of each packet if 'data'
1184 * is set). 'buf' should be large enough
1187 char *
1188 pktlist_dump (pktlist_info_t * pktlist, char *buf)
1190 char *obuf;
1191 uint i;
1193 obuf = buf;
1195 buf += sprintf (buf, "Packet list dump:\n");
1197 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]))
1204 /* Print pkttag */
1205 buf += sprintf (buf, "Pkttag(in hex): ");
1206 buf +=
1207 bcm_format_hex (buf, PKTTAG (pktlist->list[i]), OSL_PKTTAG_SZ);
1209 buf += sprintf (buf, "Pktdata(in hex): ");
1210 buf += bcm_format_hex (buf, PKTDATA (NULL, pktlist->list[i]),
1211 PKTLEN (NULL, pktlist->list[i]));
1212 #endif /* NOTDEF */
1214 buf += sprintf (buf, "\n");
1216 return obuf;
1218 #endif /* BCMDBG_PKT */
1220 #if 0
1221 /* iovar table lookup */
1222 const bcm_iovar_t *
1223 bcm_iovar_lookup (const bcm_iovar_t * table, const char *name)
1225 const bcm_iovar_t *vi;
1226 const char *lookup_name;
1228 /* skip any ':' delimited option prefixes */
1229 lookup_name = strrchr (name, ':');
1230 if (lookup_name != NULL)
1231 lookup_name++;
1232 else
1233 lookup_name = name;
1235 ASSERT (table);
1237 for (vi = table; vi->name; vi++)
1239 if (!strcmp (vi->name, lookup_name))
1240 return vi;
1242 /* ran to end of table */
1244 return NULL; /* var name not found */
1246 #endif
1249 bcm_iovar_lencheck (const bcm_iovar_t * vi, void *arg, int len, bool set)
1251 int bcmerror = 0;
1253 /* length check on io buf */
1254 switch (vi->type)
1256 case IOVT_BOOL:
1257 case IOVT_INT8:
1258 case IOVT_INT16:
1259 case IOVT_INT32:
1260 case IOVT_UINT8:
1261 case IOVT_UINT16:
1262 case IOVT_UINT32:
1263 /* all integers are int32 sized args at the ioctl interface */
1264 if (len < (int) sizeof (int))
1266 bcmerror = BCME_BUFTOOSHORT;
1268 break;
1270 case IOVT_BUFFER:
1271 /* buffer must meet minimum length requirement */
1272 if (len < vi->minlen)
1274 bcmerror = BCME_BUFTOOSHORT;
1276 break;
1278 case IOVT_VOID:
1279 if (!set)
1281 /* Cannot return nil... */
1282 bcmerror = BCME_UNSUPPORTED;
1284 else if (len)
1286 /* Set is an action w/o parameters */
1287 bcmerror = BCME_BUFTOOLONG;
1289 break;
1291 default:
1292 /* unknown type for length check in iovar info */
1293 ASSERT (0);
1294 bcmerror = BCME_UNSUPPORTED;
1297 return bcmerror;
1300 #define CRC_INNER_LOOP(n, c, x) \
1301 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1303 #if 0
1304 /*******************************************************************************
1305 * crc8
1307 * Computes a crc8 over the input data using the polynomial:
1309 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1311 * The caller provides the initial value (either CRC8_INIT_VALUE
1312 * or the previous returned value) to allow for processing of
1313 * discontiguous blocks of data. When generating the CRC the
1314 * caller is responsible for complementing the final return value
1315 * and inserting it into the byte stream. When checking, a final
1316 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1318 * Reference: Dallas Semiconductor Application Note 27
1319 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1320 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1321 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1323 * ****************************************************************************
1326 static const uint8 crc8_table[256] = {
1327 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1328 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1329 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1330 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1331 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1332 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1333 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1334 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1335 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1336 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1337 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1338 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1339 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1340 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1341 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1342 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1343 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1344 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1345 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1346 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1347 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1348 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1349 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1350 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1351 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1352 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1353 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1354 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1355 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1356 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1357 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1358 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1361 uint8 BCMROMFN (hndcrc8) (uint8 * pdata, /* pointer to array of data to process */
1362 uint nbytes, /* number of input data bytes to process */
1363 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1366 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1367 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1369 while (nbytes-- > 0)
1370 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1372 return crc;
1375 /*******************************************************************************
1376 * crc16
1378 * Computes a crc16 over the input data using the polynomial:
1380 * x^16 + x^12 +x^5 + 1
1382 * The caller provides the initial value (either CRC16_INIT_VALUE
1383 * or the previous returned value) to allow for processing of
1384 * discontiguous blocks of data. When generating the CRC the
1385 * caller is responsible for complementing the final return value
1386 * and inserting it into the byte stream. When checking, a final
1387 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1389 * Reference: Dallas Semiconductor Application Note 27
1390 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1391 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1392 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1394 * ****************************************************************************
1396 static const uint16 crc16_table[256] = {
1397 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1398 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1399 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1400 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1401 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1402 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1403 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1404 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1405 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1406 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1407 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1408 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1409 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1410 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1411 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1412 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1413 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1414 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1415 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1416 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1417 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1418 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1419 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1420 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1421 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1422 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1423 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1424 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1425 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1426 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1427 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1428 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1431 uint16 BCMROMFN (hndcrc16) (uint8 * pdata, /* pointer to array of data to process */
1432 uint nbytes, /* number of input data bytes to process */
1433 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1436 while (nbytes-- > 0)
1437 CRC_INNER_LOOP (16, crc, *pdata++);
1438 return crc;
1440 #endif
1442 static const uint32 crc32_table[256] = {
1443 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1444 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1445 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1446 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1447 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1448 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1449 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1450 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1451 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1452 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1453 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1454 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1455 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1456 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1457 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1458 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1459 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1460 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1461 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1462 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1463 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1464 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1465 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1466 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1467 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1468 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1469 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1470 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1471 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1472 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1473 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1474 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1475 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1476 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1477 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1478 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1479 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1480 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1481 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1482 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1483 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1484 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1485 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1486 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1487 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1488 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1489 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1490 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1491 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1492 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1493 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1494 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1495 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1496 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1497 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1498 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1499 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1500 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1501 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1502 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1503 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1504 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1505 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1506 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1509 uint32 BCMROMFN (hndcrc32) (uint8 * pdata, /* pointer to array of data to process */
1510 uint nbytes, /* number of input data bytes to process */
1511 uint32 crc /* either CRC32_INIT_VALUE or previous return value */
1514 uint8 *pend;
1515 #ifdef __mips__
1516 uint8 tmp[4];
1517 ulong *tptr = (ulong *) tmp;
1519 /* in case the beginning of the buffer isn't aligned */
1520 pend = (uint8 *) ((uint) (pdata + 3) & 0xfffffffc);
1521 nbytes -= (pend - pdata);
1522 while (pdata < pend)
1523 CRC_INNER_LOOP (32, crc, *pdata++);
1525 /* handle bulk of data as 32-bit words */
1526 pend = pdata + (nbytes & 0xfffffffc);
1527 while (pdata < pend)
1529 *tptr = *(ulong *) pdata;
1530 pdata += sizeof (ulong *);
1531 CRC_INNER_LOOP (32, crc, tmp[0]);
1532 CRC_INNER_LOOP (32, crc, tmp[1]);
1533 CRC_INNER_LOOP (32, crc, tmp[2]);
1534 CRC_INNER_LOOP (32, crc, tmp[3]);
1537 /* 1-3 bytes at end of buffer */
1538 pend = pdata + (nbytes & 0x03);
1539 while (pdata < pend)
1540 CRC_INNER_LOOP (32, crc, *pdata++);
1541 #else
1542 pend = pdata + nbytes;
1543 while (pdata < pend)
1544 CRC_INNER_LOOP (32, crc, *pdata++);
1545 #endif /* __mips__ */
1547 return crc;
1550 #ifdef notdef
1551 #define CLEN 1499 /* CRC Length */
1552 #define CBUFSIZ (CLEN+4)
1553 #define CNBUFS 5 /* # of bufs */
1555 void
1556 testcrc32 (void)
1558 uint j, k, l;
1559 uint8 *buf;
1560 uint len[CNBUFS];
1561 uint32 crcr;
1562 uint32 crc32tv[CNBUFS] =
1563 { 0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110 };
1565 ASSERT ((buf = MALLOC (CBUFSIZ * CNBUFS)) != NULL);
1567 /* step through all possible alignments */
1568 for (l = 0; l <= 4; l++)
1570 for (j = 0; j < CNBUFS; j++)
1572 len[j] = CLEN;
1573 for (k = 0; k < len[j]; k++)
1574 *(buf + j * CBUFSIZ + (k + l)) = (j + k) & 0xff;
1577 for (j = 0; j < CNBUFS; j++)
1579 crcr = crc32 (buf + j * CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1580 ASSERT (crcr == crc32tv[j]);
1584 MFREE (buf, CBUFSIZ * CNBUFS);
1585 return;
1587 #endif /* notdef */
1590 * Advance from the current 1-byte tag/1-byte length/variable-length value
1591 * triple, to the next, returning a pointer to the next.
1592 * If the current or next TLV is invalid (does not fit in given buffer length),
1593 * NULL is returned.
1594 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1595 * by the TLV parameter's length if it is valid.
1597 bcm_tlv_t *BCMROMFN (bcm_next_tlv) (bcm_tlv_t * elt, int *buflen)
1599 int len;
1601 /* validate current elt */
1602 if (!bcm_valid_tlv (elt, *buflen))
1603 return NULL;
1605 /* advance to next elt */
1606 len = elt->len;
1607 elt = (bcm_tlv_t *) (elt->data + len);
1608 *buflen -= (2 + len);
1610 /* validate next elt */
1611 if (!bcm_valid_tlv (elt, *buflen))
1612 return NULL;
1614 return elt;
1618 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1619 * triples, returning a pointer to the substring whose first element
1620 * matches tag
1622 bcm_tlv_t *BCMROMFN (bcm_parse_tlvs) (void *buf, int buflen, uint key)
1624 bcm_tlv_t *elt;
1625 int totlen;
1627 elt = (bcm_tlv_t *) buf;
1628 totlen = buflen;
1630 /* find tagged parameter */
1631 while (totlen >= 2)
1633 int len = elt->len;
1635 /* validate remaining totlen */
1636 if ((elt->id == key) && (totlen >= (len + 2)))
1637 return (elt);
1639 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1640 totlen -= (len + 2);
1643 return NULL;
1646 #if 0
1648 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1649 * triples, returning a pointer to the substring whose first element
1650 * matches tag. Stop parsing when we see an element whose ID is greater
1651 * than the target key.
1653 bcm_tlv_t *BCMROMFN (bcm_parse_ordered_tlvs) (void *buf, int buflen, uint key)
1655 bcm_tlv_t *elt;
1656 int totlen;
1658 elt = (bcm_tlv_t *) buf;
1659 totlen = buflen;
1661 /* find tagged parameter */
1662 while (totlen >= 2)
1664 uint id = elt->id;
1665 int len = elt->len;
1667 /* Punt if we start seeing IDs > than target key */
1668 if (id > key)
1669 return (NULL);
1671 /* validate remaining totlen */
1672 if ((id == key) && (totlen >= (len + 2)))
1673 return (elt);
1675 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1676 totlen -= (len + 2);
1678 return NULL;
1681 #ifdef BCMDBG
1683 bcm_format_flags (const bcm_bit_desc_t * bd, uint32 flags, char *buf, int len)
1685 int i;
1686 char *p = buf;
1687 char hexstr[16];
1688 int slen = 0;
1689 uint32 bit;
1690 const char *name;
1692 if (len < 2 || !buf)
1693 return 0;
1695 buf[0] = '\0';
1696 len -= 1;
1698 for (i = 0; flags != 0; i++)
1700 bit = bd[i].bit;
1701 name = bd[i].name;
1702 if (bit == 0 && flags)
1704 /* print any unnamed bits */
1705 sprintf (hexstr, "0x%X", flags);
1706 name = hexstr;
1707 flags = 0; /* exit loop */
1709 else if ((flags & bit) == 0)
1710 continue;
1711 slen += strlen (name);
1712 if (len < slen)
1713 break;
1714 if (p != buf)
1715 p += sprintf (p, " "); /* btwn flag space */
1716 strcat (p, name);
1717 p += strlen (name);
1718 flags &= ~bit;
1719 len -= slen;
1720 slen = 1; /* account for btwn flag space */
1723 /* indicate the str was too short */
1724 if (flags != 0)
1726 if (len == 0)
1727 p--; /* overwrite last char */
1728 p += sprintf (p, ">");
1731 return (int) (p - buf);
1734 void
1735 deadbeef (void *p, uint len)
1737 static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
1739 while (len-- > 0)
1741 *(uint8 *) p = meat[((uintptr) p) & 3];
1742 p = (uint8 *) p + 1;
1746 /* pretty hex print a contiguous buffer */
1747 void
1748 prhex (const char *msg, uchar * buf, uint nbytes)
1750 char line[128], *p;
1751 uint i;
1753 if (msg && (msg[0] != '\0'))
1754 printf ("%s:\n", msg);
1756 p = line;
1757 for (i = 0; i < nbytes; i++)
1759 if (i % 16 == 0)
1761 p += sprintf (p, " %04d: ", i); /* line prefix */
1763 p += sprintf (p, "%02x ", buf[i]);
1764 if (i % 16 == 15)
1766 printf ("%s\n", line); /* flush line */
1767 p = line;
1771 /* flush last partial line */
1772 if (p != line)
1773 printf ("%s\n", line);
1776 /* print bytes formatted as hex to a string. return the resulting string length */
1778 bcm_format_hex (char *str, const void *bytes, int len)
1780 int i;
1781 char *p = str;
1782 const uint8 *src = (const uint8 *) bytes;
1784 for (i = 0; i < len; i++)
1786 p += sprintf (p, "%02X", *src);
1787 src++;
1789 return (int) (p - str);
1792 #endif /* BCMDBG */
1794 /* Produce a human-readable string for boardrev */
1795 char *
1796 bcm_brev_str (uint16 brev, char *buf)
1798 if (brev < 0x100)
1799 snprintf (buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1800 else
1801 snprintf (buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A',
1802 brev & 0xfff);
1804 return (buf);
1807 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1809 /* dump large strings to console */
1810 void
1811 printfbig (char *buf)
1813 uint len, max_len;
1814 char c;
1816 len = strlen (buf);
1818 max_len = BUFSIZE_TODUMP_ATONCE;
1820 while (len > max_len)
1822 c = buf[max_len];
1823 buf[max_len] = '\0';
1824 printf ("%s", buf);
1825 buf[max_len] = c;
1827 buf += max_len;
1828 len -= max_len;
1830 /* print the remaining string */
1831 printf ("%s\n", buf);
1832 return;
1835 /* routine to dump fields in a fileddesc structure */
1836 uint
1837 bcmdumpfields (readreg_rtn read_rtn, void *arg0, void *arg1,
1838 struct fielddesc * fielddesc_array, char *buf, uint32 bufsize)
1840 uint filled_len;
1841 int len;
1842 struct fielddesc *cur_ptr;
1844 filled_len = 0;
1845 cur_ptr = fielddesc_array;
1847 while (bufsize > 1)
1849 if (cur_ptr->nameandfmt == NULL)
1850 break;
1851 len = snprintf (buf, bufsize, cur_ptr->nameandfmt,
1852 read_rtn (arg0, arg1, cur_ptr->offset));
1853 /* check for snprintf overflow or error */
1854 if (len < 0 || (uint32) len >= bufsize)
1855 len = bufsize - 1;
1856 buf += len;
1857 bufsize -= len;
1858 filled_len += len;
1859 cur_ptr++;
1861 return filled_len;
1863 #endif
1865 uint
1866 bcm_mkiovar (char *name, char *data, uint datalen, char *buf, uint buflen)
1868 uint len;
1870 len = strlen (name) + 1;
1872 if ((len + datalen) > buflen)
1873 return 0;
1875 strncpy (buf, name, buflen);
1877 /* append data onto the end of the name string */
1878 memcpy (&buf[len], data, datalen);
1879 len += datalen;
1881 return len;
1884 /* Quarter dBm units to mW
1885 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1886 * Table is offset so the last entry is largest mW value that fits in
1887 * a uint16.
1890 #define QDBM_OFFSET 153 /* Offset for first entry */
1891 #define QDBM_TABLE_LEN 40 /* Table size */
1893 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1894 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1896 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1898 /* Largest mW value that will round down to the last table entry,
1899 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1900 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1902 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1904 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1905 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1906 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1907 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1908 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1909 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1910 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1913 uint16 BCMROMFN (bcm_qdbm_to_mw) (uint8 qdbm)
1915 uint factor = 1;
1916 int idx = qdbm - QDBM_OFFSET;
1918 if (idx > QDBM_TABLE_LEN)
1920 /* clamp to max uint16 mW value */
1921 return 0xFFFF;
1924 /* scale the qdBm index up to the range of the table 0-40
1925 * where an offset of 40 qdBm equals a factor of 10 mW.
1927 while (idx < 0)
1929 idx += 40;
1930 factor *= 10;
1933 /* return the mW value scaled down to the correct factor of 10,
1934 * adding in factor/2 to get proper rounding.
1936 return ((nqdBm_to_mW_map[idx] + factor / 2) / factor);
1939 uint8 BCMROMFN (bcm_mw_to_qdbm) (uint16 mw)
1941 uint8 qdbm;
1942 int offset;
1943 uint mw_uint = mw;
1944 uint boundary;
1946 /* handle boundary case */
1947 if (mw_uint <= 1)
1948 return 0;
1950 offset = QDBM_OFFSET;
1952 /* move mw into the range of the table */
1953 while (mw_uint < QDBM_TABLE_LOW_BOUND)
1955 mw_uint *= 10;
1956 offset -= 40;
1959 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++)
1961 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1962 nqdBm_to_mW_map[qdbm]) / 2;
1963 if (mw_uint < boundary)
1964 break;
1967 qdbm += (uint8) offset;
1969 return (qdbm);
1973 uint BCMROMFN (bcm_bitcount) (uint8 * bitmap, uint length)
1975 uint bitcount = 0, i;
1976 uint8 tmp;
1977 for (i = 0; i < length; i++)
1979 tmp = bitmap[i];
1980 while (tmp)
1982 bitcount++;
1983 tmp &= (tmp - 1);
1986 return bitcount;
1990 /* Initialization of bcmstrbuf structure */
1991 void
1992 bcm_binit (struct bcmstrbuf *b, char *buf, uint size)
1994 b->origsize = b->size = size;
1995 b->origbuf = b->buf = buf;
1998 /* Buffer sprintf wrapper to guard against buffer overflow */
2000 bcm_bprintf (struct bcmstrbuf *b, const char *fmt, ...)
2002 va_list ap;
2003 int r;
2005 va_start (ap, fmt);
2006 r = vsnprintf (b->buf, b->size, fmt, ap);
2008 /* Non Ansi C99 compliant returns -1,
2009 * Ansi compliant return r >= b->size,
2010 * bcmstdlib returns 0, handle all
2012 if ((r == -1) || (r >= (int) b->size) || (r == 0))
2014 b->size = 0;
2016 else
2018 b->size -= r;
2019 b->buf += r;
2022 va_end (ap);
2024 return r;
2027 char *
2028 bcm_ether_ntoa (struct ether_addr *ea, char *buf)
2030 snprintf (buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
2031 ea->octet[0] & 0xff, ea->octet[1] & 0xff, ea->octet[2] & 0xff,
2032 ea->octet[3] & 0xff, ea->octet[4] & 0xff, ea->octet[5] & 0xff);
2033 return (buf);