2 * Driver O/S-independent utility routines
4 * Copyright 2006, Broadcom Corporation
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.
25 #endif /* BCMDRIVER */
26 #if defined(NDIS) || defined(__vxworks) || defined(_CFE_)
28 #include <bcmstdlib.h>
30 #include <bcmendian.h>
32 #include <proto/ethernet.h>
33 #include <proto/vlan.h>
34 #include <proto/bcmip.h>
35 #include <proto/802.1d.h>
42 /* nvram vars cache */
43 static char *nvram_vars = NULL;
44 static int vars_len = -1;
46 /* copy a pkt buffer chain into a buffer */
48 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
53 len = 4096; /* "infinite" */
55 /* skip 'offset' bytes */
56 for (; p && offset; p = PKTNEXT(osh, p)) {
57 if (offset < (uint)PKTLEN(osh, p))
59 offset -= PKTLEN(osh, p);
66 for (; p && len; p = PKTNEXT(osh, p)) {
67 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
68 bcopy(PKTDATA(osh, p) + offset, buf, n);
78 /* return total length of buffer chain */
80 pkttotlen(osl_t *osh, void *p)
85 for (; p; p = PKTNEXT(osh, p))
86 total += PKTLEN(osh, p);
90 /* return the last buffer of chained pkt */
92 pktlast(osl_t *osh, void *p)
94 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
102 * osl multiple-precedence packet queue
103 * hi_prec is always >= the number of the highest non-empty queue
106 pktq_penq(struct pktq *pq, int prec, void *p)
110 ASSERT(prec >= 0 && prec < pq->num_prec);
111 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
113 ASSERT(!pktq_full(pq));
114 ASSERT(!pktq_pfull(pq, prec));
119 PKTSETLINK(q->tail, p);
128 if (pq->hi_prec < prec)
129 pq->hi_prec = (uint8)prec;
135 pktq_penq_head(struct pktq *pq, int prec, void *p)
139 ASSERT(prec >= 0 && prec < pq->num_prec);
140 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
142 ASSERT(!pktq_full(pq));
143 ASSERT(!pktq_pfull(pq, prec));
150 PKTSETLINK(p, q->head);
156 if (pq->hi_prec < prec)
157 pq->hi_prec = (uint8)prec;
163 pktq_pdeq(struct pktq *pq, int prec)
168 ASSERT(prec >= 0 && prec < pq->num_prec);
172 if ((p = q->head) == NULL)
175 if ((q->head = PKTLINK(p)) == NULL)
188 pktq_pdeq_tail(struct pktq *pq, int prec)
193 ASSERT(prec >= 0 && prec < pq->num_prec);
197 if ((p = q->head) == NULL)
200 for (prev = NULL; p != q->tail; p = PKTLINK(p))
204 PKTSETLINK(prev, NULL);
217 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
225 q->head = PKTLINK(p);
227 PKTFREE(osh, p, dir);
237 pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
242 ASSERT(prec >= 0 && prec < pq->num_prec);
249 if (q->head == pktbuf) {
250 if ((q->head = PKTLINK(pktbuf)) == NULL)
253 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
258 PKTSETLINK(p, PKTLINK(pktbuf));
259 if (q->tail == pktbuf)
265 PKTSETLINK(pktbuf, NULL);
270 pktq_init(struct pktq *pq, int num_prec, int max_len)
274 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
276 /* pq is variable size; only zero out what's requested */
277 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
279 pq->num_prec = (uint16)num_prec;
281 pq->max = (uint16)max_len;
283 for (prec = 0; prec < num_prec; prec++)
284 pq->q[prec].max = pq->max;
288 pktq_deq(struct pktq *pq, int *prec_out)
297 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
302 if ((p = q->head) == NULL)
305 if ((q->head = PKTLINK(p)) == NULL)
321 pktq_deq_tail(struct pktq *pq, int *prec_out)
330 for (prec = 0; prec < pq->hi_prec; prec++)
331 if (pq->q[prec].head)
336 if ((p = q->head) == NULL)
339 for (prev = NULL; p != q->tail; p = PKTLINK(p))
343 PKTSETLINK(prev, NULL);
361 pktq_peek(struct pktq *pq, int *prec_out)
368 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
374 return (pq->q[prec].head);
378 pktq_peek_tail(struct pktq *pq, int *prec_out)
385 for (prec = 0; prec < pq->hi_prec; prec++)
386 if (pq->q[prec].head)
392 return (pq->q[prec].tail);
396 pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
399 for (prec = 0; prec < pq->num_prec; prec++)
400 pktq_pflush(osh, pq, prec, dir);
401 ASSERT(pq->len == 0);
404 /* Return sum of lengths of a specific set of precedences */
406 pktq_mlen(struct pktq *pq, uint prec_bmp)
412 for (prec = 0; prec <= pq->hi_prec; prec++)
413 if (prec_bmp & (1 << prec))
414 len += pq->q[prec].len;
419 /* Priority dequeue from a specific set of precedences */
421 pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
430 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
433 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
439 if ((p = q->head) == NULL)
442 if ((q->head = PKTLINK(p)) == NULL)
457 #ifndef BCMROMOFFLOAD
459 const unsigned char bcm_ctype[] = {
460 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
461 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
463 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
464 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
465 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
466 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
467 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
468 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
469 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
470 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
471 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
472 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
473 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
474 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
475 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
476 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
477 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
478 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
479 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
480 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
481 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
482 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
483 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
484 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
485 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
486 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
487 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
488 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
489 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
490 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
491 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
492 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
496 BCMROMFN(bcm_strtoul)(char *cp, char **endp, uint base)
503 while (bcm_isspace(*cp))
508 else if (cp[0] == '-') {
515 if ((cp[1] == 'x') || (cp[1] == 'X')) {
524 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
530 while (bcm_isxdigit(*cp) &&
531 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
532 result = result*base + value;
537 result = (ulong)(result * -1);
546 BCMROMFN(bcm_atoi)(char *s)
548 return (int)bcm_strtoul(s, NULL, 10);
551 /* return pointer to location of substring 'needle' in 'haystack' */
553 BCMROMFN(bcmstrstr)(char *haystack, char *needle)
558 if ((haystack == NULL) || (needle == NULL))
561 nlen = strlen(needle);
562 len = strlen(haystack) - nlen + 1;
564 for (i = 0; i < len; i++)
565 if (bcmp(needle, &haystack[i], nlen) == 0)
566 return (&haystack[i]);
571 BCMROMFN(bcmstrcat)(char *dest, const char *src)
573 strcpy(&dest[strlen(dest)], src);
577 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
579 BCMROMFN(bcm_ether_atoe)(char *p, struct ether_addr *ea)
584 ea->octet[i++] = (char) bcm_strtoul(p, &p, 16);
591 #endif /* !BCMROMOFFLOAD */
593 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
594 /* registry routine buffer preparation utility functions:
595 * parameter order is like strncpy, but returns count
596 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
612 /* wbuflen is in bytes */
613 wbuflen /= sizeof(ushort);
615 for (i = 0; i < wbuflen; ++i) {
618 *abuf++ = (char) *wbuf++;
625 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
628 bcm_ether_ntoa(struct ether_addr *ea, char *buf)
630 sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
631 ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff,
632 ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff);
641 for (i = 0; i < ms; i++) {
647 * Search the name=value vars for a specific one and return its value.
648 * Returns NULL if not found.
651 getvar(char *vars, const char *name)
661 /* first look in vars[] */
662 for (s = vars; s && *s;) {
664 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
671 /* then query nvram */
672 return (nvram_get(name));
673 #endif /* _MINOSL_ */
677 * Search the vars for a specific one and return its value as
678 * an integer. Returns 0 if not found.
681 getintvar(char *vars, const char *name)
688 if ((val = getvar(vars, name)) == NULL)
691 return (bcm_strtoul(val, NULL, 0));
692 #endif /* _MINOSL_ */
696 /* Search for token in comma separated token-string */
698 findmatch(char *string, char *name)
705 while ((c = strchr(string, ',')) != NULL) {
706 if (len == (uint)(c - string) && !strncmp(string, name, len))
711 return (!strcmp(string, name));
714 /* Return gpio pin number assigned to the named pin */
716 * Variable should be in format:
718 * gpio<N>=pin_name,pin_name
720 * This format allows multiple features to share the gpio with mutual
723 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
724 * and if def_pin is not used by others.
727 getgpiopin(char *vars, char *pin_name, uint def_pin)
729 char name[] = "gpioXXXX";
733 /* Go thru all possibilities till a match in pin name */
734 for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
735 sprintf(name, "gpio%d", pin);
736 val = getvar(vars, name);
737 if (val && findmatch(val, pin_name))
741 if (def_pin != GPIO_PIN_NOTDEFINED) {
742 /* make sure the default pin is not used by someone else */
743 sprintf(name, "gpio%d", def_pin);
744 if (getvar(vars, name)) {
745 def_pin = GPIO_PIN_NOTDEFINED;
754 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
762 /* last entry logged */
763 static uint logi = 0;
764 /* next entry to read */
765 static uint readi = 0;
770 BCMPERF_ENABLE_INSTRCOUNT();
771 BCMPERF_ENABLE_ICACHE_MISS();
772 BCMPERF_ENABLE_ICACHE_HIT();
776 bcmlog(char *fmt, uint a1, uint a2)
778 static uint last = 0;
780 OSL_GETCYCLES(cycles);
784 logtab[i].cycles = cycles - last;
789 logi = (i + 1) % LOGSIZE;
797 static uint last = 0;
798 static uint32 ic_miss = 0;
799 static uint32 instr_count = 0;
801 uint32 instr_count_cur;
804 OSL_GETCYCLES(cycles);
805 BCMPERF_GETICACHE_MISS(ic_miss_cur);
806 BCMPERF_GETINSTRCOUNT(instr_count_cur);
810 logtab[i].cycles = cycles - last;
811 logtab[i].a1 = ic_miss_cur - ic_miss;
812 logtab[i].a2 = instr_count_cur - instr_count;
815 logi = (i + 1) % LOGSIZE;
818 instr_count = instr_count_cur;
819 ic_miss = ic_miss_cur;
824 bcmdumplog(char *buf, int size)
830 limit = buf + size - 80;
838 /* print in chronological order */
840 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
841 if (logtab[readi].fmt == NULL)
844 buf += sprintf(buf, "%d\t", logtab[readi].cycles);
845 buf += sprintf(buf, logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
846 buf += sprintf(buf, "\n");
853 * Dump one log entry at a time.
854 * Return index of next entry or -1 when no more .
857 bcmdumplogent(char *buf, uint i)
862 * If buf is NULL, return the starting index,
863 * interpreting i as the indicator of last 'i' entries to dump.
866 i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
867 return ((logi - i) % LOGSIZE);
878 for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) {
879 if (logtab[i].fmt == NULL)
881 buf += sprintf(buf, "%d: %d\t", i, logtab[i].cycles);
882 buf += sprintf(buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
883 buf += sprintf(buf, "\n");
890 #endif /* BCMPERFSTATS */
893 /* pretty hex print a pkt buffer chain */
895 prpkt(const char *msg, osl_t *osh, void *p0)
899 if (msg && (msg[0] != '\0'))
900 printf("%s:\n", msg);
902 for (p = p0; p; p = PKTNEXT(osh, p))
903 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
907 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
908 * Also updates the inplace vlan tag if requested.
909 * For debugging, it returns an indication of what it did.
912 pktsetprio(void *pkt, bool update_vtag)
914 struct ether_header *eh;
915 struct ethervlan_header *evh;
920 pktdata = (uint8 *) PKTDATA(NULL, pkt);
921 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
923 eh = (struct ether_header *) pktdata;
925 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
927 int vlan_prio, dscp_prio = 0;
929 evh = (struct ethervlan_header *)eh;
931 vlan_tag = ntoh16(evh->vlan_tag);
932 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
934 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
935 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
936 uint8 tos_tc = IP_TOS(ip_body);
937 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
940 /* DSCP priority gets precedence over 802.1P (vlan tag) */
941 if (dscp_prio != 0) {
942 priority = dscp_prio;
945 priority = vlan_prio;
949 * If the DSCP priority is not the same as the VLAN priority,
950 * then overwrite the priority field in the vlan tag, with the
951 * DSCP priority value. This is required for Linux APs because
952 * the VLAN driver on Linux, overwrites the skb->priority field
953 * with the priority value in the vlan tag
955 if (update_vtag && (priority != vlan_prio)) {
956 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
957 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
958 evh->vlan_tag = hton16(vlan_tag);
961 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
962 uint8 *ip_body = pktdata + sizeof(struct ether_header);
963 uint8 tos_tc = IP_TOS(ip_body);
964 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
968 ASSERT(priority >= 0 && priority <= MAXPRIO);
969 PKTSETPRIO(pkt, priority);
970 return (rc | priority);
973 static char bcm_undeferrstr[BCME_STRLEN];
975 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
977 /* Convert the Error codes into related Error strings */
979 bcmerrorstr(int bcmerror)
983 abs_bcmerror = ABS(bcmerror);
985 /* check if someone added a bcmerror code but forgot to add errorstring */
986 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
987 if ((bcmerror > 0) || (abs_bcmerror > ABS(BCME_LAST))) {
988 sprintf(bcm_undeferrstr, "undefined Error %d", bcmerror);
989 return bcm_undeferrstr;
992 ASSERT((strlen(bcmerrorstrtable[abs_bcmerror])) < BCME_STRLEN);
994 return bcmerrorstrtable[abs_bcmerror];
998 BCMINITFN(bcm_nvram_refresh)(char *flash)
1005 /* default "empty" vars cache */
1008 if ((ret = nvram_getall(flash, NVRAM_SPACE)))
1011 /* determine nvram length */
1012 for (i = 0; i < NVRAM_SPACE; i++) {
1013 if (flash[i] == '\0' && flash[i+1] == '\0')
1024 bcm_nvram_vars(uint *length)
1027 /* cache may be stale if nvram is read/write */
1029 ASSERT(!bcmreclaimed);
1030 bcm_nvram_refresh(nvram_vars);
1038 /* copy nvram vars into locally-allocated multi-string array */
1040 BCMINITFN(bcm_nvram_cache)(void *sbh)
1046 if (vars_len >= 0) {
1048 bcm_nvram_refresh(nvram_vars);
1053 osh = sb_osh((sb_t *)sbh);
1055 /* allocate memory and read in flash */
1056 if (!(flash = MALLOC(osh, NVRAM_SPACE))) {
1061 bcm_nvram_refresh(flash);
1065 /* copy into a properly-sized buffer */
1066 if (!(nvram_vars = MALLOC(osh, vars_len))) {
1069 bcopy(flash, nvram_vars, vars_len);
1071 MFREE(osh, flash, NVRAM_SPACE);
1073 /* cache must be full size of nvram if read/write */
1075 #endif /* BCMNVRAMR */
1081 #ifdef BCMDBG_PKT /* pkt logging for debugging */
1082 /* Add a packet to the pktlist */
1084 pktlist_add(pktlist_info_t *pktlist, void *pkt)
1087 ASSERT(pktlist->count < PKTLIST_SIZE);
1089 /* Verify the packet is not already part of the list */
1090 for (i = 0; i < pktlist->count; i++) {
1091 if (pktlist->list[i] == pkt)
1094 pktlist->list[pktlist->count] = pkt;
1099 /* Remove a packet from the pktlist */
1101 pktlist_remove(pktlist_info_t *pktlist, void *pkt)
1104 uint num = pktlist->count;
1106 /* find the index where pkt exists */
1107 for (i = 0; i < num; i++)
1109 /* check for the existence of pkt in the list */
1110 if (pktlist->list[i] == pkt)
1112 /* replace with the last element */
1113 pktlist->list[i] = pktlist->list[num-1];
1121 /* Dump the pktlist (and the contents of each packet if 'data'
1122 * is set). 'buf' should be large enough
1126 pktlist_dump(pktlist_info_t *pktlist, char *buf)
1133 buf += sprintf(buf, "Packet list dump:\n");
1135 for (i = 0; i < (pktlist->count); i++) {
1136 buf += sprintf(buf, "0x%p\t", pktlist->list[i]);
1138 #ifdef NOTDEF /* Remove this ifdef to print pkttag and pktdata */
1139 if (PKTTAG(pktlist->list[i])) {
1141 buf += sprintf(buf, "Pkttag(in hex): ");
1142 buf += bcm_format_hex(buf, PKTTAG(pktlist->list[i]), OSL_PKTTAG_SZ);
1144 buf += sprintf(buf, "Pktdata(in hex): ");
1145 buf += bcm_format_hex(buf, PKTDATA(NULL, pktlist->list[i]),
1146 PKTLEN(NULL, pktlist->list[i]));
1149 buf += sprintf(buf, "\n");
1153 #endif /* BCMDBG_PKT */
1155 /* iovar table lookup */
1157 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1159 const bcm_iovar_t *vi;
1160 const char *lookup_name;
1162 /* skip any ':' delimited option prefixes */
1163 lookup_name = strrchr(name, ':');
1164 if (lookup_name != NULL)
1171 for (vi = table; vi->name; vi++) {
1172 if (!strcmp(vi->name, lookup_name))
1175 /* ran to end of table */
1177 return NULL; /* var name not found */
1181 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1185 /* length check on io buf */
1194 /* all integers are int32 sized args at the ioctl interface */
1195 if (len < (int)sizeof(int)) {
1196 bcmerror = BCME_BUFTOOSHORT;
1201 /* buffer must meet minimum length requirement */
1202 if (len < vi->minlen) {
1203 bcmerror = BCME_BUFTOOSHORT;
1209 /* Cannot return nil... */
1210 bcmerror = BCME_UNSUPPORTED;
1212 /* Set is an action w/o parameters */
1213 bcmerror = BCME_BUFTOOLONG;
1218 /* unknown type for length check in iovar info */
1220 bcmerror = BCME_UNSUPPORTED;
1226 #endif /* BCMDRIVER */
1229 #ifndef BCMROMOFFLOAD
1230 /*******************************************************************************
1233 * Computes a crc8 over the input data using the polynomial:
1235 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1237 * The caller provides the initial value (either CRC8_INIT_VALUE
1238 * or the previous returned value) to allow for processing of
1239 * discontiguous blocks of data. When generating the CRC the
1240 * caller is responsible for complementing the final return value
1241 * and inserting it into the byte stream. When checking, a final
1242 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1244 * Reference: Dallas Semiconductor Application Note 27
1245 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1246 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1247 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1249 * ****************************************************************************
1252 static const uint8 crc8_table[256] = {
1253 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1254 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1255 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1256 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1257 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1258 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1259 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1260 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1261 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1262 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1263 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1264 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1265 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1266 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1267 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1268 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1269 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1270 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1271 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1272 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1273 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1274 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1275 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1276 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1277 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1278 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1279 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1280 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1281 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1282 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1283 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1284 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1287 #define CRC_INNER_LOOP(n, c, x) \
1288 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1292 uint8 *pdata, /* pointer to array of data to process */
1293 uint nbytes, /* number of input data bytes to process */
1294 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1297 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1298 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1300 while (nbytes-- > 0)
1301 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1306 /*******************************************************************************
1309 * Computes a crc16 over the input data using the polynomial:
1311 * x^16 + x^12 +x^5 + 1
1313 * The caller provides the initial value (either CRC16_INIT_VALUE
1314 * or the previous returned value) to allow for processing of
1315 * discontiguous blocks of data. When generating the CRC the
1316 * caller is responsible for complementing the final return value
1317 * and inserting it into the byte stream. When checking, a final
1318 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1320 * Reference: Dallas Semiconductor Application Note 27
1321 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1322 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1323 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1325 * ****************************************************************************
1328 static const uint16 crc16_table[256] = {
1329 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1330 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1331 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1332 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1333 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1334 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1335 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1336 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1337 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1338 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1339 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1340 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1341 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1342 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1343 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1344 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1345 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1346 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1347 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1348 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1349 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1350 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1351 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1352 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1353 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1354 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1355 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1356 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1357 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1358 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1359 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1360 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1365 uint8 *pdata, /* pointer to array of data to process */
1366 uint nbytes, /* number of input data bytes to process */
1367 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1370 while (nbytes-- > 0)
1371 CRC_INNER_LOOP(16, crc, *pdata++);
1375 static const uint32 crc32_table[256] = {
1376 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1377 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1378 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1379 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1380 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1381 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1382 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1383 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1384 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1385 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1386 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1387 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1388 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1389 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1390 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1391 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1392 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1393 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1394 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1395 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1396 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1397 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1398 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1399 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1400 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1401 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1402 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1403 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1404 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1405 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1406 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1407 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1408 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1409 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1410 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1411 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1412 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1413 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1414 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1415 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1416 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1417 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1418 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1419 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1420 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1421 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1422 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1423 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1424 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1425 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1426 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1427 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1428 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1429 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1430 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1431 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1432 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1433 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1434 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1435 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1436 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1437 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1438 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1439 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1444 uint8 *pdata, /* pointer to array of data to process */
1445 uint nbytes, /* number of input data bytes to process */
1446 uint32 crc /* either CRC32_INIT_VALUE or previous return value */
1452 ulong *tptr = (ulong *)tmp;
1454 /* in case the beginning of the buffer isn't aligned */
1455 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
1456 nbytes -= (pend - pdata);
1457 while (pdata < pend)
1458 CRC_INNER_LOOP(32, crc, *pdata++);
1460 /* handle bulk of data as 32-bit words */
1461 pend = pdata + (nbytes & 0xfffffffc);
1462 while (pdata < pend) {
1463 *tptr = *(ulong *)pdata;
1464 pdata += sizeof(ulong *);
1465 CRC_INNER_LOOP(32, crc, tmp[0]);
1466 CRC_INNER_LOOP(32, crc, tmp[1]);
1467 CRC_INNER_LOOP(32, crc, tmp[2]);
1468 CRC_INNER_LOOP(32, crc, tmp[3]);
1471 /* 1-3 bytes at end of buffer */
1472 pend = pdata + (nbytes & 0x03);
1473 while (pdata < pend)
1474 CRC_INNER_LOOP(32, crc, *pdata++);
1476 pend = pdata + nbytes;
1477 while (pdata < pend)
1478 CRC_INNER_LOOP(32, crc, *pdata++);
1479 #endif /* __mips__ */
1485 #define CLEN 1499 /* CRC Length */
1486 #define CBUFSIZ (CLEN+4)
1487 #define CNBUFS 5 /* # of bufs */
1489 void testcrc32(void)
1495 uint32 crc32tv[CNBUFS] =
1496 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1498 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1500 /* step through all possible alignments */
1501 for (l = 0; l <= 4; l++) {
1502 for (j = 0; j < CNBUFS; j++) {
1504 for (k = 0; k < len[j]; k++)
1505 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1508 for (j = 0; j < CNBUFS; j++) {
1509 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1510 ASSERT(crcr == crc32tv[j]);
1514 MFREE(buf, CBUFSIZ*CNBUFS);
1520 * Advance from the current 1-byte tag/1-byte length/variable-length value
1521 * triple, to the next, returning a pointer to the next.
1522 * If the current or next TLV is invalid (does not fit in given buffer length),
1524 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1525 * by the TLV paramter's length if it is valid.
1528 BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen)
1532 /* validate current elt */
1533 if (!bcm_valid_tlv(elt, *buflen))
1536 /* advance to next elt */
1538 elt = (bcm_tlv_t*)(elt->data + len);
1539 *buflen -= (2 + len);
1541 /* validate next elt */
1542 if (!bcm_valid_tlv(elt, *buflen))
1549 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1550 * triples, returning a pointer to the substring whose first element
1554 BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key)
1559 elt = (bcm_tlv_t*)buf;
1562 /* find tagged parameter */
1563 while (totlen >= 2) {
1566 /* validate remaining totlen */
1567 if ((elt->id == key) && (totlen >= (len + 2)))
1570 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1571 totlen -= (len + 2);
1578 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1579 * triples, returning a pointer to the substring whose first element
1580 * matches tag. Stop parsing when we see an element whose ID is greater
1581 * than the target key.
1584 BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key)
1589 elt = (bcm_tlv_t*)buf;
1592 /* find tagged parameter */
1593 while (totlen >= 2) {
1597 /* Punt if we start seeing IDs > than target key */
1601 /* validate remaining totlen */
1602 if ((id == key) && (totlen >= (len + 2)))
1605 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1606 totlen -= (len + 2);
1610 #endif /* !BCMROMOFFLOAD */
1614 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1623 if (len < 2 || !buf)
1629 for (i = 0; flags != 0; i++) {
1632 if (bit == 0 && flags) {
1633 /* print any unnamed bits */
1634 sprintf(hexstr, "0x%X", flags);
1636 flags = 0; /* exit loop */
1637 } else if ((flags & bit) == 0)
1639 slen += strlen(name);
1642 if (p != buf) p += sprintf(p, " "); /* btwn flag space */
1647 slen = 1; /* account for btwn flag space */
1650 /* indicate the str was too short */
1653 p--; /* overwrite last char */
1654 p += sprintf(p, ">");
1657 return (int)(p - buf);
1661 deadbeef(void *p, uint len)
1663 static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
1666 *(uint8*)p = meat[((uintptr)p) & 3];
1671 /* pretty hex print a contiguous buffer */
1673 prhex(const char *msg, uchar *buf, uint nbytes)
1678 if (msg && (msg[0] != '\0'))
1679 printf("%s:\n", msg);
1682 for (i = 0; i < nbytes; i++) {
1684 p += sprintf(p, " %04d: ", i); /* line prefix */
1686 p += sprintf(p, "%02x ", buf[i]);
1688 printf("%s\n", line); /* flush line */
1693 /* flush last partial line */
1695 printf("%s\n", line);
1698 /* print bytes formatted as hex to a string. return the resulting string length */
1700 bcm_format_hex(char *str, const void *bytes, int len)
1704 const uint8 *src = (const uint8*)bytes;
1706 for (i = 0; i < len; i++) {
1707 p += sprintf(p, "%02X", *src);
1710 return (int)(p - str);
1715 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1717 /* dump large strings to console */
1719 printfbig(char *buf)
1726 max_len = BUFSIZE_TODUMP_ATONCE;
1728 while (len > max_len) {
1730 buf[max_len] = '\0';
1737 /* print the remaining string */
1738 printf("%s\n", buf);
1741 /* routine to dump fields in a fileddesc structure */
1743 bcmdumpfields(readreg_rtn read_rtn, void *arg0, void *arg1, struct fielddesc *fielddesc_array,
1744 char *buf, uint32 bufsize)
1748 struct fielddesc *cur_ptr;
1751 cur_ptr = fielddesc_array;
1753 while (bufsize > (filled_len + 64)) {
1754 if (cur_ptr->nameandfmt == NULL)
1756 len = sprintf(buf, cur_ptr->nameandfmt, read_rtn(arg0, arg1, cur_ptr->offset));
1765 bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1769 len = strlen(name) + 1;
1771 if ((len + datalen) > buflen)
1776 /* append data onto the end of the name string */
1777 memcpy(&buf[len], data, datalen);
1783 /* Quarter dBm units to mW
1784 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1785 * Table is offset so the last entry is largest mW value that fits in
1789 #define QDBM_OFFSET 153 /* Offset for first entry */
1790 #define QDBM_TABLE_LEN 40 /* Table size */
1792 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1793 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1795 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1797 /* Largest mW value that will round down to the last table entry,
1798 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1799 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1801 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1803 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1804 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1805 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1806 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1807 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1808 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1809 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1813 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm)
1816 int idx = qdbm - QDBM_OFFSET;
1818 if (idx > QDBM_TABLE_LEN) {
1819 /* clamp to max uint16 mW value */
1823 /* scale the qdBm index up to the range of the table 0-40
1824 * where an offset of 40 qdBm equals a factor of 10 mW.
1831 /* return the mW value scaled down to the correct factor of 10,
1832 * adding in factor/2 to get proper rounding.
1834 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
1838 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw)
1845 /* handle boundary case */
1849 offset = QDBM_OFFSET;
1851 /* move mw into the range of the table */
1852 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1857 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
1858 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
1859 nqdBm_to_mW_map[qdbm])/2;
1860 if (mw_uint < boundary) break;
1863 qdbm += (uint8)offset;
1870 BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint length)
1872 uint bitcount = 0, i;
1874 for (i = 0; i < length; i++) {
1886 /* Initialization of bcmstrbuf structure */
1888 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1890 b->origsize = b->size = size;
1891 b->origbuf = b->buf = buf;
1894 /* Buffer sprintf wrapper to guard against buffer overflow */
1896 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1902 r = vsnprintf(b->buf, b->size, fmt, ap);
1904 /* Non Ansi C99 compliant returns -1,
1905 * Ansi compliant return r >= b->size,
1906 * bcmstdlib returns 0, handle all
1908 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1919 #endif /* BCMDRIVER */