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