2 * Driver O/S-independent utility routines
4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved.
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * $Id: bcmutils.c 401759 2013-05-13 16:08:08Z $
23 #if defined(__FreeBSD__) || defined(__NetBSD__)
24 #include <sys/param.h>
25 #if __NetBSD_Version__ >= 500000003
26 #include <sys/stdarg.h>
28 #include <machine/stdarg.h>
40 #else /* !BCMDRIVER */
46 #if defined(BCMEXTSUP)
51 #endif /* !BCMDRIVER */
53 #if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || defined(_CFE_)
54 #include <bcmstdlib.h>
56 #include <bcmendian.h>
58 #include <proto/ethernet.h>
59 #include <proto/vlan.h>
60 #include <proto/bcmip.h>
61 #include <proto/802.1d.h>
62 #include <proto/802.11.h>
66 #include <proto/bcmipv6.h>
67 void *_bcmutils_dummy_fn
= NULL
;
72 /* nvram vars cache */
73 static char *nvram_vars
= NULL
;
74 static int vars_len
= -1;
78 BCMATTACHFN(pktpool_init
)(osl_t
*osh
, pktpool_t
*pktp
, int *pplen
, int plen
, bool istx
)
86 ASSERT(pplen
!= NULL
);
90 bzero(pktp
, sizeof(pktpool_t
));
92 pktp
->istx
= istx
? TRUE
: FALSE
;
93 pktp
->plen
= (uint16
)plen
;
96 pktp
->maxlen
= PKTPOOL_LEN_MAX
;
97 if (pktplen
> pktp
->maxlen
)
98 pktplen
= pktp
->maxlen
;
100 for (i
= 0; i
< pktplen
; i
++) {
101 p
= PKTGET(osh
, plen
, pktp
->istx
);
103 /* Not able to allocate all requested pkts
104 * so just return what was actually allocated
105 * We can add to the pool later
113 PKTSETPOOL(osh
, p
, TRUE
, pktp
);
118 pktp
->dbg_q
[pktp
->dbg_qlen
++].p
= p
;
124 pktp
->len
++; /* Add one for end */
129 BCMATTACHFN(pktpool_deinit
)(osl_t
*osh
, pktpool_t
*pktp
)
135 ASSERT(pktp
!= NULL
);
138 for (i
= 0; i
< cnt
; i
++) {
139 if (pktp
->q
[i
] != NULL
) {
140 PKTSETPOOL(osh
, pktp
->q
[i
], FALSE
, NULL
);
141 PKTFREE(osh
, pktp
->q
[i
], pktp
->istx
);
146 if (pktp
->dbg_q
[i
].p
!= NULL
)
147 pktp
->dbg_q
[i
].p
= NULL
;
150 pktp
->inited
= FALSE
;
152 /* Are there still pending pkts? */
153 ASSERT(pktpool_len(pktp
) == 0);
159 pktpool_fill(osl_t
*osh
, pktpool_t
*pktp
, bool minimal
)
163 int len
, psize
, maxlen
;
165 ASSERT(pktpool_plen(pktp
) != 0);
167 maxlen
= pktpool_maxlen(pktp
);
168 psize
= minimal
? (maxlen
>> 2) : maxlen
;
169 len
= pktpool_len(pktp
);
170 for (; len
< psize
; len
++) {
171 p
= PKTGET(osh
, pktpool_plen(pktp
), FALSE
);
177 if (pktpool_add(pktp
, p
) != BCME_OK
) {
178 PKTFREE(osh
, p
, FALSE
);
188 pktpool_avail(pktpool_t
*pktp
)
190 if (pktp
->w
== pktp
->r
)
193 return (pktp
->w
> pktp
->r
) ? (pktp
->w
- pktp
->r
) : ((pktp
->len
) - (pktp
->r
- pktp
->w
));
197 pktpool_deq(pktpool_t
*pktp
)
201 if (pktp
->r
== pktp
->w
)
204 p
= pktp
->q
[pktp
->r
];
207 pktp
->q
[pktp
->r
++] = NULL
;
208 pktp
->r
%= (pktp
->len
);
214 pktpool_enq(pktpool_t
*pktp
, void *p
)
220 next
= (pktp
->w
+ 1) % (pktp
->len
);
221 if (next
== pktp
->r
) {
222 /* Should not happen; otherwise pkt leak */
227 ASSERT(pktp
->q
[pktp
->w
] == NULL
);
229 pktp
->q
[pktp
->w
] = p
;
234 BCMATTACHFN(pktpool_avail_register
)(pktpool_t
*pktp
, pktpool_cb_t cb
, void *arg
)
241 if (i
== PKTPOOL_CB_MAX
)
244 ASSERT(pktp
->cbs
[i
].cb
== NULL
);
245 pktp
->cbs
[i
].cb
= cb
;
246 pktp
->cbs
[i
].arg
= arg
;
253 BCMATTACHFN(pktpool_empty_register
)(pktpool_t
*pktp
, pktpool_cb_t cb
, void *arg
)
260 if (i
== PKTPOOL_CB_MAX
)
263 ASSERT(pktp
->ecbs
[i
].cb
== NULL
);
264 pktp
->ecbs
[i
].cb
= cb
;
265 pktp
->ecbs
[i
].arg
= arg
;
272 pktpool_empty_notify(pktpool_t
*pktp
)
277 for (i
= 0; i
< pktp
->ecbcnt
; i
++) {
278 ASSERT(pktp
->ecbs
[i
].cb
!= NULL
);
279 pktp
->ecbs
[i
].cb(pktp
, pktp
->ecbs
[i
].arg
);
288 pktpool_dbg_register(pktpool_t
*pktp
, pktpool_cb_t cb
, void *arg
)
295 if (i
== PKTPOOL_CB_MAX
)
298 ASSERT(pktp
->dbg_cbs
[i
].cb
== NULL
);
299 pktp
->dbg_cbs
[i
].cb
= cb
;
300 pktp
->dbg_cbs
[i
].arg
= arg
;
306 int pktpool_dbg_notify(pktpool_t
*pktp
);
309 pktpool_dbg_notify(pktpool_t
*pktp
)
313 for (i
= 0; i
< pktp
->dbg_cbcnt
; i
++) {
314 ASSERT(pktp
->dbg_cbs
[i
].cb
);
315 pktp
->dbg_cbs
[i
].cb(pktp
, pktp
->dbg_cbs
[i
].arg
);
322 pktpool_dbg_dump(pktpool_t
*pktp
)
326 printf("pool len=%d maxlen=%d\n", pktp
->dbg_qlen
, pktp
->maxlen
);
327 for (i
= 0; i
< pktp
->dbg_qlen
; i
++) {
328 ASSERT(pktp
->dbg_q
[i
].p
);
329 printf("%d, p: 0x%x dur:%lu us state:%d\n", i
,
330 pktp
->dbg_q
[i
].p
, pktp
->dbg_q
[i
].dur
/100, PKTPOOLSTATE(pktp
->dbg_q
[i
].p
));
337 pktpool_stats_dump(pktpool_t
*pktp
, pktpool_stats_t
*stats
)
342 bzero(stats
, sizeof(pktpool_stats_t
));
343 for (i
= 0; i
< pktp
->dbg_qlen
; i
++) {
344 ASSERT(pktp
->dbg_q
[i
].p
!= NULL
);
346 state
= PKTPOOLSTATE(pktp
->dbg_q
[i
].p
);
351 stats
->txdh
++; break;
353 stats
->txd11
++; break;
355 stats
->rxdh
++; break;
357 stats
->rxd11
++; break;
359 stats
->rxfill
++; break;
361 stats
->idle
++; break;
369 pktpool_start_trigger(pktpool_t
*pktp
, void *p
)
373 if (!PKTPOOL(NULL
, p
))
376 OSL_GETCYCLES(cycles
);
378 for (i
= 0; i
< pktp
->dbg_qlen
; i
++) {
379 ASSERT(pktp
->dbg_q
[i
].p
!= NULL
);
381 if (pktp
->dbg_q
[i
].p
== p
) {
382 pktp
->dbg_q
[i
].cycles
= cycles
;
390 int pktpool_stop_trigger(pktpool_t
*pktp
, void *p
);
392 pktpool_stop_trigger(pktpool_t
*pktp
, void *p
)
396 if (!PKTPOOL(NULL
, p
))
399 OSL_GETCYCLES(cycles
);
401 for (i
= 0; i
< pktp
->dbg_qlen
; i
++) {
402 ASSERT(pktp
->dbg_q
[i
].p
!= NULL
);
404 if (pktp
->dbg_q
[i
].p
== p
) {
405 if (pktp
->dbg_q
[i
].cycles
== 0)
408 if (cycles
>= pktp
->dbg_q
[i
].cycles
)
409 pktp
->dbg_q
[i
].dur
= cycles
- pktp
->dbg_q
[i
].cycles
;
412 (((uint32
)-1) - pktp
->dbg_q
[i
].cycles
) + cycles
+ 1;
414 pktp
->dbg_q
[i
].cycles
= 0;
421 #endif /* BCMDBG_POOL */
424 pktpool_avail_notify_normal(osl_t
*osh
, pktpool_t
*pktp
)
427 pktp
->availcb_excl
= NULL
;
432 pktpool_avail_notify_exclusive(osl_t
*osh
, pktpool_t
*pktp
, pktpool_cb_t cb
)
437 ASSERT(pktp
->availcb_excl
== NULL
);
438 for (i
= 0; i
< pktp
->cbcnt
; i
++) {
439 if (cb
== pktp
->cbs
[i
].cb
) {
440 pktp
->availcb_excl
= &pktp
->cbs
[i
];
445 if (pktp
->availcb_excl
== NULL
)
452 pktpool_avail_notify(pktpool_t
*pktp
)
458 if (pktp
->availcb_excl
!= NULL
) {
459 pktp
->availcb_excl
->cb(pktp
, pktp
->availcb_excl
->arg
);
464 for (i
= 0; i
< pktp
->cbcnt
; i
++) {
465 avail
= pktpool_avail(pktp
);
473 ASSERT(pktp
->cbs
[idx
].cb
!= NULL
);
474 pktp
->cbs
[idx
].cb(pktp
, pktp
->cbs
[idx
].arg
);
478 /* Alternate between filling from head or tail
486 pktpool_get(pktpool_t
*pktp
)
490 p
= pktpool_deq(pktp
);
493 /* Notify and try to reclaim tx pkts */
495 pktpool_empty_notify(pktp
);
497 p
= pktpool_deq(pktp
);
504 pktpool_free(pktpool_t
*pktp
, void *p
)
509 /* pktpool_stop_trigger(pktp, p); */
512 pktpool_enq(pktp
, p
);
514 if (pktp
->emptycb_disable
)
518 if (pktp
->empty
== FALSE
)
519 pktpool_avail_notify(pktp
);
524 pktpool_add(pktpool_t
*pktp
, void *p
)
528 if (pktpool_len(pktp
) == pktp
->maxlen
)
531 ASSERT(pktpool_plen(pktp
) == PKTLEN(NULL
, p
)); /* pkts in pool have same length */
532 PKTSETPOOL(NULL
, p
, TRUE
, pktp
);
535 if (pktp
->r
> pktp
->w
) {
537 ASSERT(pktp
->q
[pktp
->len
- 1] == NULL
);
538 pktp
->q
[pktp
->len
- 1] = p
;
540 pktpool_enq(pktp
, p
);
543 pktp
->dbg_q
[pktp
->dbg_qlen
++].p
= p
;
550 pktpool_setmaxlen(pktpool_t
*pktp
, uint16 maxlen
)
552 if (maxlen
> PKTPOOL_LEN_MAX
)
553 maxlen
= PKTPOOL_LEN_MAX
;
555 /* if pool is already beyond maxlen, then just cap it
556 * since we currently do not reduce the pool len
559 pktp
->maxlen
= (pktpool_len(pktp
) > maxlen
) ? pktpool_len(pktp
) : maxlen
;
565 pktpool_emptycb_disable(pktpool_t
*pktp
, bool disable
)
569 pktp
->emptycb_disable
= disable
;
573 pktpool_emptycb_disabled(pktpool_t
*pktp
)
576 return pktp
->emptycb_disable
;
579 /* copy a pkt buffer chain into a buffer */
581 pktcopy(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
586 len
= 4096; /* "infinite" */
588 /* skip 'offset' bytes */
589 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
590 if (offset
< (uint
)PKTLEN(osh
, p
))
592 offset
-= PKTLEN(osh
, p
);
599 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
600 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
601 bcopy(PKTDATA(osh
, p
) + offset
, buf
, n
);
611 /* copy a buffer into a pkt buffer chain */
613 pktfrombuf(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
617 /* skip 'offset' bytes */
618 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
619 if (offset
< (uint
)PKTLEN(osh
, p
))
621 offset
-= PKTLEN(osh
, p
);
628 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
629 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
630 bcopy(buf
, PKTDATA(osh
, p
) + offset
, n
);
641 /* copy data from one pkt buffer (chain) to another */
643 pkt2pktcopy(osl_t
*osh
, void *p1
, uint offs1
, void *p2
, uint offs2
, int maxlen
)
646 uint len1
, len2
, copylen
, totallen
;
648 for (; p1
&& offs
; p1
= PKTNEXT(osh
, p1
)) {
649 if (offs1
< (uint
)PKTLEN(osh
, p1
))
651 offs1
-= PKTLEN(osh
, p1
);
653 for (; p2
&& offs
; p2
= PKTNEXT(osh
, p2
)) {
654 if (offs2
< (uint
)PKTLEN(osh
, p2
))
656 offs2
-= PKTLEN(osh
, p2
);
659 /* Heck w/it, only need the above for now */
664 /* return total length of buffer chain */
666 pkttotlen(osl_t
*osh
, void *p
)
672 for (; p
; p
= PKTNEXT(osh
, p
)) {
673 len
= PKTLEN(osh
, p
);
676 /* Bad packet length, just drop and exit */
677 printf("wl: pkttotlen bad (%p,%d)\n", p
, len
);
687 /* return the last buffer of chained pkt */
689 pktlast(osl_t
*osh
, void *p
)
691 for (; PKTNEXT(osh
, p
); p
= PKTNEXT(osh
, p
))
697 /* count segments of a chained packet */
699 pktsegcnt(osl_t
*osh
, void *p
)
703 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
))
710 /* count segments of a chained packet */
712 pktsegcnt_war(osl_t
*osh
, void *p
)
716 uint len
, remain
, align64
;
718 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
)) {
720 len
= PKTLEN(osh
, p
);
722 pktdata
= (uint8
*)PKTDATA(osh
, p
); /* starting address of data */
723 /* Check for page boundary straddle (2048B) */
724 if (((uintptr
)pktdata
& ~0x7ff) != ((uintptr
)(pktdata
+len
) & ~0x7ff))
727 align64
= (uint
)((uintptr
)pktdata
& 0x3f); /* aligned to 64B */
728 align64
= (64 - align64
) & 0x3f;
729 len
-= align64
; /* bytes from aligned 64B to end */
730 /* if aligned to 128B, check for MOD 128 between 1 to 4B */
732 if (remain
> 0 && remain
<= 4)
733 cnt
++; /* add extra seg */
741 pktdataoffset(osl_t
*osh
, void *p
, uint offset
)
743 uint total
= pkttotlen(osh
, p
);
744 uint pkt_off
= 0, len
= 0;
745 uint8
*pdata
= (uint8
*) PKTDATA(osh
, p
);
750 for (; p
; p
= PKTNEXT(osh
, p
)) {
751 pdata
= (uint8
*) PKTDATA(osh
, p
);
752 pkt_off
= offset
- len
;
753 len
+= PKTLEN(osh
, p
);
757 return (uint8
*) (pdata
+pkt_off
);
761 /* given a offset in pdata, find the pkt seg hdr */
763 pktoffset(osl_t
*osh
, void *p
, uint offset
)
765 uint total
= pkttotlen(osh
, p
);
771 for (; p
; p
= PKTNEXT(osh
, p
)) {
772 len
+= PKTLEN(osh
, p
);
780 * osl multiple-precedence packet queue
781 * hi_prec is always >= the number of the highest non-empty precedence
784 pktq_penq(struct pktq
*pq
, int prec
, void *p
)
788 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
789 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
791 ASSERT(!pktq_full(pq
));
792 ASSERT(!pktq_pfull(pq
, prec
));
797 PKTSETLINK(q
->tail
, p
);
806 if (pq
->hi_prec
< prec
)
807 pq
->hi_prec
= (uint8
)prec
;
813 pktq_penq_head(struct pktq
*pq
, int prec
, void *p
)
817 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
818 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
820 ASSERT(!pktq_full(pq
));
821 ASSERT(!pktq_pfull(pq
, prec
));
828 PKTSETLINK(p
, q
->head
);
834 if (pq
->hi_prec
< prec
)
835 pq
->hi_prec
= (uint8
)prec
;
841 pktq_pdeq(struct pktq
*pq
, int prec
)
846 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
850 if ((p
= q
->head
) == NULL
)
853 if ((q
->head
= PKTLINK(p
)) == NULL
)
866 pktq_pdeq_prev(struct pktq
*pq
, int prec
, void *prev_p
)
871 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
878 if ((p
= PKTLINK(prev_p
)) == NULL
)
888 PKTSETLINK(prev_p
, PKTLINK(p
));
895 pktq_pdeq_tail(struct pktq
*pq
, int prec
)
900 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
904 if ((p
= q
->head
) == NULL
)
907 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
911 PKTSETLINK(prev
, NULL
);
924 pktq_pflush(osl_t
*osh
, struct pktq
*pq
, int prec
, bool dir
, ifpkt_cb_t fn
, int arg
)
927 void *p
, *prev
= NULL
;
932 if (fn
== NULL
|| (*fn
)(p
, arg
)) {
933 bool head
= (p
== q
->head
);
935 q
->head
= PKTLINK(p
);
937 PKTSETLINK(prev
, PKTLINK(p
));
939 PKTFREE(osh
, p
, dir
);
942 p
= (head
? q
->head
: PKTLINK(prev
));
949 if (q
->head
== NULL
) {
956 pktq_pdel(struct pktq
*pq
, void *pktbuf
, int prec
)
961 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
968 if (q
->head
== pktbuf
) {
969 if ((q
->head
= PKTLINK(pktbuf
)) == NULL
)
972 for (p
= q
->head
; p
&& PKTLINK(p
) != pktbuf
; p
= PKTLINK(p
))
977 PKTSETLINK(p
, PKTLINK(pktbuf
));
978 if (q
->tail
== pktbuf
)
984 PKTSETLINK(pktbuf
, NULL
);
989 pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
993 ASSERT(num_prec
> 0 && num_prec
<= PKTQ_MAX_PREC
);
995 /* pq is variable size; only zero out what's requested */
996 bzero(pq
, OFFSETOF(struct pktq
, q
) + (sizeof(struct pktq_prec
) * num_prec
));
998 pq
->num_prec
= (uint16
)num_prec
;
1000 pq
->max
= (uint16
)max_len
;
1002 for (prec
= 0; prec
< num_prec
; prec
++)
1003 pq
->q
[prec
].max
= pq
->max
;
1007 pktq_set_max_plen(struct pktq
*pq
, int prec
, int max_len
)
1009 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
1011 if (prec
< pq
->num_prec
)
1012 pq
->q
[prec
].max
= (uint16
)max_len
;
1016 pktq_deq(struct pktq
*pq
, int *prec_out
)
1018 struct pktq_prec
*q
;
1025 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1030 if ((p
= q
->head
) == NULL
)
1033 if ((q
->head
= PKTLINK(p
)) == NULL
)
1043 PKTSETLINK(p
, NULL
);
1049 pktq_deq_tail(struct pktq
*pq
, int *prec_out
)
1051 struct pktq_prec
*q
;
1058 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
1059 if (pq
->q
[prec
].head
)
1064 if ((p
= q
->head
) == NULL
)
1067 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
1071 PKTSETLINK(prev
, NULL
);
1083 PKTSETLINK(p
, NULL
);
1089 pktq_peek(struct pktq
*pq
, int *prec_out
)
1096 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1102 return (pq
->q
[prec
].head
);
1106 pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
1113 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
1114 if (pq
->q
[prec
].head
)
1120 return (pq
->q
[prec
].tail
);
1124 pktq_flush(osl_t
*osh
, struct pktq
*pq
, bool dir
, ifpkt_cb_t fn
, int arg
)
1128 /* Optimize flush, if pktq len = 0, just return.
1129 * pktq len of 0 means pktq's prec q's are all empty.
1135 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
1136 pktq_pflush(osh
, pq
, prec
, dir
, fn
, arg
);
1138 ASSERT(pq
->len
== 0);
1141 /* Return sum of lengths of a specific set of precedences */
1143 pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
1149 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
1150 if (prec_bmp
& (1 << prec
))
1151 len
+= pq
->q
[prec
].len
;
1156 /* Priority peek from a specific set of precedences */
1158 pktq_mpeek(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
1160 struct pktq_prec
*q
;
1168 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1171 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
1177 if ((p
= q
->head
) == NULL
)
1185 /* Priority dequeue from a specific set of precedences */
1187 pktq_mdeq(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
1189 struct pktq_prec
*q
;
1196 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1199 while ((pq
->q
[prec
].head
== NULL
) || ((prec_bmp
& (1 << prec
)) == 0))
1205 if ((p
= q
->head
) == NULL
)
1208 if ((q
->head
= PKTLINK(p
)) == NULL
)
1218 PKTSETLINK(p
, NULL
);
1223 #endif /* BCMDRIVER */
1225 #if defined(BCMROMBUILD)
1226 const unsigned char BCMROMDATA(bcm_ctype
)[] = {
1228 const unsigned char bcm_ctype
[] = {
1231 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 0-7 */
1232 _BCM_C
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
,
1234 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 16-23 */
1235 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 24-31 */
1236 _BCM_S
|_BCM_SP
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 32-39 */
1237 _BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 40-47 */
1238 _BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
, /* 48-55 */
1239 _BCM_D
,_BCM_D
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 56-63 */
1240 _BCM_P
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
,
1241 _BCM_U
|_BCM_X
, _BCM_U
, /* 64-71 */
1242 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 72-79 */
1243 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 80-87 */
1244 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 88-95 */
1245 _BCM_P
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
,
1246 _BCM_L
|_BCM_X
, _BCM_L
, /* 96-103 */
1247 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 104-111 */
1248 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 112-119 */
1249 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_C
, /* 120-127 */
1250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
1251 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
1252 _BCM_S
|_BCM_SP
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
1253 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 160-175 */
1254 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
1255 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 176-191 */
1256 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
,
1257 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, /* 192-207 */
1258 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_P
, _BCM_U
, _BCM_U
, _BCM_U
,
1259 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_L
, /* 208-223 */
1260 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
,
1261 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, /* 224-239 */
1262 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_P
, _BCM_L
, _BCM_L
, _BCM_L
,
1263 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
/* 240-255 */
1267 BCMROMFN(bcm_strtoul
)(const char *cp
, char **endp
, uint base
)
1269 ulong result
, last_result
= 0, value
;
1274 while (bcm_isspace(*cp
))
1279 else if (cp
[0] == '-') {
1286 if ((cp
[1] == 'x') || (cp
[1] == 'X')) {
1295 } else if (base
== 16 && (cp
[0] == '0') && ((cp
[1] == 'x') || (cp
[1] == 'X'))) {
1301 while (bcm_isxdigit(*cp
) &&
1302 (value
= bcm_isdigit(*cp
) ? *cp
-'0' : bcm_toupper(*cp
)-'A'+10) < base
) {
1303 result
= result
*base
+ value
;
1304 /* Detected overflow */
1305 if (result
< last_result
&& !minus
)
1307 last_result
= result
;
1312 result
= (ulong
)(-(long)result
);
1315 *endp
= DISCARD_QUAL(cp
, char);
1321 BCMROMFN(bcm_atoi
)(const char *s
)
1323 return (int)bcm_strtoul(s
, NULL
, 10);
1326 /* return pointer to location of substring 'needle' in 'haystack' */
1328 BCMROMFN(bcmstrstr
)(const char *haystack
, const char *needle
)
1333 if ((haystack
== NULL
) || (needle
== NULL
))
1334 return DISCARD_QUAL(haystack
, char);
1336 nlen
= strlen(needle
);
1337 len
= strlen(haystack
) - nlen
+ 1;
1339 for (i
= 0; i
< len
; i
++)
1340 if (memcmp(needle
, &haystack
[i
], nlen
) == 0)
1341 return DISCARD_QUAL(&haystack
[i
], char);
1346 BCMROMFN(bcmstrcat
)(char *dest
, const char *src
)
1350 p
= dest
+ strlen(dest
);
1352 while ((*p
++ = *src
++) != '\0')
1359 BCMROMFN(bcmstrncat
)(char *dest
, const char *src
, uint size
)
1364 p
= dest
+ strlen(dest
);
1367 while (p
!= endp
&& (*p
++ = *src
++) != '\0')
1374 /****************************************************************************
1375 * Function: bcmstrtok
1378 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
1379 * but allows strToken() to be used by different strings or callers at the same
1380 * time. Each call modifies '*string' by substituting a NULL character for the
1381 * first delimiter that is encountered, and updates 'string' to point to the char
1382 * after the delimiter. Leading delimiters are skipped.
1385 * string (mod) Ptr to string ptr, updated by token.
1386 * delimiters (in) Set of delimiter characters.
1387 * tokdelim (out) Character that delimits the returned token. (May
1388 * be set to NULL if token delimiter is not required).
1390 * Returns: Pointer to the next token found. NULL when no more tokens are found.
1391 *****************************************************************************
1394 bcmstrtok(char **string
, const char *delimiters
, char *tokdelim
)
1397 unsigned long map
[8];
1401 if (tokdelim
!= NULL
) {
1402 /* Prime the token delimiter */
1406 /* Clear control map */
1407 for (count
= 0; count
< 8; count
++) {
1411 /* Set bits in delimiter table */
1413 map
[*delimiters
>> 5] |= (1 << (*delimiters
& 31));
1415 while (*delimiters
++);
1417 str
= (unsigned char*)*string
;
1419 /* Find beginning of token (skip over leading delimiters). Note that
1420 * there is no token iff this loop sets str to point to the terminal
1421 * null (*str == '\0')
1423 while (((map
[*str
>> 5] & (1 << (*str
& 31))) && *str
) || (*str
== ' ')) {
1427 nextoken
= (char*)str
;
1429 /* Find the end of the token. If it is not the end of the string,
1432 for (; *str
; str
++) {
1433 if (map
[*str
>> 5] & (1 << (*str
& 31))) {
1434 if (tokdelim
!= NULL
) {
1443 *string
= (char*)str
;
1445 /* Determine if a token has been found. */
1446 if (nextoken
== (char *) str
) {
1455 #define xToLower(C) \
1456 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
1459 /****************************************************************************
1460 * Function: bcmstricmp
1462 * Purpose: Compare to strings case insensitively.
1464 * Parameters: s1 (in) First string to compare.
1465 * s2 (in) Second string to compare.
1467 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1468 * t1 > t2, when ignoring case sensitivity.
1469 *****************************************************************************
1472 bcmstricmp(const char *s1
, const char *s2
)
1476 while (*s2
&& *s1
) {
1479 if (dc
< sc
) return -1;
1480 if (dc
> sc
) return 1;
1485 if (*s1
&& !*s2
) return 1;
1486 if (!*s1
&& *s2
) return -1;
1491 /****************************************************************************
1492 * Function: bcmstrnicmp
1494 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
1497 * Parameters: s1 (in) First string to compare.
1498 * s2 (in) Second string to compare.
1499 * cnt (in) Max characters to compare.
1501 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1502 * t1 > t2, when ignoring case sensitivity.
1503 *****************************************************************************
1506 bcmstrnicmp(const char* s1
, const char* s2
, int cnt
)
1510 while (*s2
&& *s1
&& cnt
) {
1513 if (dc
< sc
) return -1;
1514 if (dc
> sc
) return 1;
1521 if (*s1
&& !*s2
) return 1;
1522 if (!*s1
&& *s2
) return -1;
1526 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
1528 BCMROMFN(bcm_ether_atoe
)(const char *p
, struct ether_addr
*ea
)
1534 ea
->octet
[i
++] = (char) bcm_strtoul(p
, &ep
, 16);
1536 if (!*p
++ || i
== 6)
1544 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
1545 /* registry routine buffer preparation utility functions:
1546 * parameter order is like strncpy, but returns count
1547 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
1550 wchar2ascii(char *abuf
, ushort
*wbuf
, ushort wbuflen
, ulong abuflen
)
1558 /* wbuflen is in bytes */
1559 wbuflen
/= sizeof(ushort
);
1561 for (i
= 0; i
< wbuflen
; ++i
) {
1564 *abuf
++ = (char) *wbuf
++;
1571 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
1574 bcm_ether_ntoa(const struct ether_addr
*ea
, char *buf
)
1576 static const char hex
[] =
1578 '0', '1', '2', '3', '4', '5', '6', '7',
1579 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1581 const uint8
*octet
= ea
->octet
;
1585 for (i
= 0; i
< 6; i
++, octet
++) {
1586 *p
++ = hex
[(*octet
>> 4) & 0xf];
1587 *p
++ = hex
[*octet
& 0xf];
1597 bcm_ip_ntoa(struct ipv4_addr
*ia
, char *buf
)
1599 snprintf(buf
, 16, "%d.%d.%d.%d",
1600 ia
->addr
[0], ia
->addr
[1], ia
->addr
[2], ia
->addr
[3]);
1605 bcm_ipv6_ntoa(void *ipv6
, char *buf
)
1607 /* Implementing RFC 5952 Sections 4 + 5 */
1608 /* Not thoroughly tested */
1609 uint16
*a
= (uint16
*)ipv6
;
1611 int i
, i_max
= -1, cnt
= 0, cnt_max
= 1;
1614 for (i
= 0; i
< IPV6_ADDR_LEN
/2; i
++) {
1616 if (cnt
> cnt_max
) {
1624 if (cnt
> cnt_max
) {
1629 /* IPv4-translated: ::ffff:0:a.b.c.d */
1630 ((cnt_max
== 4 && a
[4] == 0xffff && a
[5] == 0) ||
1631 /* IPv4-mapped: ::ffff:a.b.c.d */
1632 (cnt_max
== 5 && a
[5] == 0xffff)))
1633 a4
= (uint8
*) (a
+ 6);
1635 for (i
= 0; i
< IPV6_ADDR_LEN
/2; i
++) {
1636 if ((uint8
*) (a
+ i
) == a4
) {
1637 snprintf(p
, 16, ":%u.%u.%u.%u", a4
[0], a4
[1], a4
[2], a4
[3]);
1639 } else if (i
== i_max
) {
1647 p
+= snprintf(p
, 8, "%x", ntoh16(a
[i
]));
1661 for (i
= 0; i
< ms
; i
++) {
1667 * Search the name=value vars for a specific one and return its value.
1668 * Returns NULL if not found.
1671 getvar(char *vars
, const char *name
)
1686 /* first look in vars[] */
1687 for (s
= vars
; s
&& *s
;) {
1688 if ((bcmp(s
, name
, len
) == 0) && (s
[len
] == '='))
1695 /* then query nvram */
1696 return (nvram_get(name
));
1697 #endif /* defined(_MINOSL_) */
1701 * Search the vars for a specific one and return its value as
1702 * an integer. Returns 0 if not found.
1705 getintvar(char *vars
, const char *name
)
1712 if ((val
= getvar(vars
, name
)) == NULL
)
1715 return (bcm_strtoul(val
, NULL
, 0));
1716 #endif /* _MINOSL_ */
1720 getintvararray(char *vars
, const char *name
, int index
)
1729 if ((buf
= getvar(vars
, name
)) == NULL
) {
1733 /* table values are always separated by "," or " " */
1734 while (*buf
!= '\0') {
1735 val
= bcm_strtoul(buf
, &endp
, 0);
1740 /* delimiter is ',' */
1746 #endif /* _MINOSL_ */
1750 getintvararraysize(char *vars
, const char *name
)
1759 if ((buf
= getvar(vars
, name
)) == NULL
) {
1763 /* table values are always separated by "," or " " */
1764 while (*buf
!= '\0') {
1765 val
= bcm_strtoul(buf
, &endp
, 0);
1767 /* delimiter is ',' */
1774 #endif /* _MINOSL_ */
1777 /* Search for token in comma separated token-string */
1779 findmatch(const char *string
, const char *name
)
1785 while ((c
= strchr(string
, ',')) != NULL
) {
1786 if (len
== (uint
)(c
- string
) && !strncmp(string
, name
, len
))
1791 return (!strcmp(string
, name
));
1794 /* Return gpio pin number assigned to the named pin
1796 * Variable should be in format:
1798 * gpio<N>=pin_name,pin_name
1800 * This format allows multiple features to share the gpio with mutual
1803 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
1804 * and if def_pin is not used by others.
1807 getgpiopin(char *vars
, char *pin_name
, uint def_pin
)
1809 char name
[] = "gpioXXXX";
1813 /* Go thru all possibilities till a match in pin name */
1814 for (pin
= 0; pin
< GPIO_NUMPINS
; pin
++) {
1815 snprintf(name
, sizeof(name
), "gpio%d", pin
);
1816 val
= getvar(vars
, name
);
1817 if (val
&& findmatch(val
, pin_name
))
1821 if (def_pin
!= GPIO_PIN_NOTDEFINED
) {
1822 /* make sure the default pin is not used by someone else */
1823 snprintf(name
, sizeof(name
), "gpio%d", def_pin
);
1824 if (getvar(vars
, name
)) {
1825 def_pin
= GPIO_PIN_NOTDEFINED
;
1831 #if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
1833 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
1841 /* last entry logged */
1842 static uint logi
= 0;
1843 /* next entry to read */
1844 static uint readi
= 0;
1845 #endif /* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */
1851 BCMPERF_ENABLE_INSTRCOUNT();
1852 BCMPERF_ENABLE_ICACHE_MISS();
1853 BCMPERF_ENABLE_ICACHE_HIT();
1856 /* WARNING: This routine uses OSL_GETCYCLES(), which can give unexpected results on
1857 * modern speed stepping CPUs. Use bcmtslog() instead in combination with TSF counter.
1860 bcmlog(char *fmt
, uint a1
, uint a2
)
1862 static uint last
= 0;
1864 OSL_GETCYCLES(cycles
);
1868 logtab
[i
].cycles
= cycles
- last
;
1869 logtab
[i
].fmt
= fmt
;
1873 logi
= (i
+ 1) % LOGSIZE
;
1881 static uint last
= 0;
1882 static uint32 ic_miss
= 0;
1883 static uint32 instr_count
= 0;
1885 uint32 instr_count_cur
;
1888 OSL_GETCYCLES(cycles
);
1889 BCMPERF_GETICACHE_MISS(ic_miss_cur
);
1890 BCMPERF_GETINSTRCOUNT(instr_count_cur
);
1894 logtab
[i
].cycles
= cycles
- last
;
1895 logtab
[i
].a1
= ic_miss_cur
- ic_miss
;
1896 logtab
[i
].a2
= instr_count_cur
- instr_count
;
1897 logtab
[i
].fmt
= fmt
;
1899 logi
= (i
+ 1) % LOGSIZE
;
1902 instr_count
= instr_count_cur
;
1903 ic_miss
= ic_miss_cur
;
1908 bcmdumplog(char *buf
, int size
)
1914 limit
= buf
+ size
- 80;
1922 /* print in chronological order */
1924 for (j
= 0; j
< num
&& (buf
< limit
); readi
= (readi
+ 1) % LOGSIZE
, j
++) {
1925 if (logtab
[readi
].fmt
== NULL
)
1927 buf
+= snprintf(buf
, (limit
- buf
), "%d\t", logtab
[readi
].cycles
);
1928 buf
+= snprintf(buf
, (limit
- buf
), logtab
[readi
].fmt
, logtab
[readi
].a1
,
1930 buf
+= snprintf(buf
, (limit
- buf
), "\n");
1937 * Dump one log entry at a time.
1938 * Return index of next entry or -1 when no more .
1941 bcmdumplogent(char *buf
, uint i
)
1946 * If buf is NULL, return the starting index,
1947 * interpreting i as the indicator of last 'i' entries to dump.
1950 i
= ((i
> 0) && (i
< (LOGSIZE
- 1))) ? i
: (LOGSIZE
- 1);
1951 return ((logi
- i
) % LOGSIZE
);
1956 ASSERT(i
< LOGSIZE
);
1962 for (; (i
!= logi
) && !hit
; i
= (i
+ 1) % LOGSIZE
) {
1963 if (logtab
[i
].fmt
== NULL
)
1965 buf
+= sprintf(buf
, "%d: %d\t", i
, logtab
[i
].cycles
);
1966 buf
+= sprintf(buf
, logtab
[i
].fmt
, logtab
[i
].a1
, logtab
[i
].a2
);
1967 buf
+= sprintf(buf
, "\n");
1974 #endif /* BCMPERFSTATS */
1976 #if defined(BCMTSTAMPEDLOGS)
1977 /* Store a TSF timestamp and a log line in the log buffer */
1979 bcmtslog(uint32 tstamp
, char *fmt
, uint a1
, uint a2
)
1982 bool use_delta
= FALSE
;
1983 static uint32 last
= 0; /* used only when use_delta is true */
1985 logtab
[i
].cycles
= tstamp
;
1987 logtab
[i
].cycles
-= last
;
1989 logtab
[i
].fmt
= fmt
;
1995 logi
= (i
+ 1) % LOGSIZE
;
1998 /* Print out a microsecond timestamp as "sec.ms.us " */
2000 bcmprinttstamp(uint32 ticks
)
2004 us
= (ticks
% TSF_TICKS_PER_MS
) * 1000 / TSF_TICKS_PER_MS
;
2005 ms
= ticks
/ TSF_TICKS_PER_MS
;
2008 printf("%04u.%03u.%03u ", sec
, ms
, us
);
2011 /* Print out the log buffer with timestamps */
2013 bcmprinttslogs(void)
2022 /* Format and print the log entries directly in chronological order */
2023 for (j
= 0; j
< num
; readi
= (readi
+ 1) % LOGSIZE
, j
++) {
2024 if (logtab
[readi
].fmt
== NULL
)
2026 bcmprinttstamp(logtab
[readi
].cycles
);
2027 printf(logtab
[readi
].fmt
, logtab
[readi
].a1
, logtab
[readi
].a2
);
2033 bcmdumptslog(char *buf
, int size
)
2040 limit
= buf
+ size
- 80;
2048 /* print in chronological order */
2049 for (j
= 0; j
< num
&& (buf
< limit
); readi
= (readi
+ 1) % LOGSIZE
, j
++) {
2050 if (logtab
[readi
].fmt
== NULL
)
2052 us
= (logtab
[readi
].cycles
% TSF_TICKS_PER_MS
) * 1000 / TSF_TICKS_PER_MS
;
2053 ms
= logtab
[readi
].cycles
/ TSF_TICKS_PER_MS
;
2057 buf
+= snprintf(buf
, (limit
- buf
), "%04u.%03u.%03u ", sec
, ms
, us
);
2058 /* buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles); */
2059 buf
+= snprintf(buf
, (limit
- buf
), logtab
[readi
].fmt
, logtab
[readi
].a1
,
2061 buf
+= snprintf(buf
, (limit
- buf
), "\n");
2065 #endif /* BCMTSTAMPEDLOGS */
2067 #if defined(BCMDBG) || defined(DHD_DEBUG)
2068 /* pretty hex print a pkt buffer chain */
2070 prpkt(const char *msg
, osl_t
*osh
, void *p0
)
2074 if (msg
&& (msg
[0] != '\0'))
2075 printf("%s:\n", msg
);
2077 for (p
= p0
; p
; p
= PKTNEXT(osh
, p
))
2078 prhex(NULL
, PKTDATA(osh
, p
), PKTLEN(osh
, p
));
2080 #endif /* BCMDBG || DHD_DEBUG */
2082 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
2083 * Also updates the inplace vlan tag if requested.
2084 * For debugging, it returns an indication of what it did.
2087 pktsetprio(void *pkt
, bool update_vtag
)
2089 struct ether_header
*eh
;
2090 struct ethervlan_header
*evh
;
2095 pktdata
= (uint8
*)PKTDATA(NULL
, pkt
);
2096 ASSERT(ISALIGNED((uintptr
)pktdata
, sizeof(uint16
)));
2098 eh
= (struct ether_header
*) pktdata
;
2100 if (eh
->ether_type
== hton16(ETHER_TYPE_8021Q
)) {
2102 int vlan_prio
, dscp_prio
= 0;
2104 evh
= (struct ethervlan_header
*)eh
;
2106 vlan_tag
= ntoh16(evh
->vlan_tag
);
2107 vlan_prio
= (int) (vlan_tag
>> VLAN_PRI_SHIFT
) & VLAN_PRI_MASK
;
2109 if (evh
->ether_type
== hton16(ETHER_TYPE_IP
)) {
2110 uint8
*ip_body
= pktdata
+ sizeof(struct ethervlan_header
);
2111 uint8 tos_tc
= IP_TOS46(ip_body
);
2112 dscp_prio
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
2115 /* DSCP priority gets precedence over 802.1P (vlan tag) */
2116 if (dscp_prio
!= 0) {
2117 priority
= dscp_prio
;
2118 rc
|= PKTPRIO_VDSCP
;
2120 priority
= vlan_prio
;
2124 * If the DSCP priority is not the same as the VLAN priority,
2125 * then overwrite the priority field in the vlan tag, with the
2126 * DSCP priority value. This is required for Linux APs because
2127 * the VLAN driver on Linux, overwrites the skb->priority field
2128 * with the priority value in the vlan tag
2130 if (update_vtag
&& (priority
!= vlan_prio
)) {
2131 vlan_tag
&= ~(VLAN_PRI_MASK
<< VLAN_PRI_SHIFT
);
2132 vlan_tag
|= (uint16
)priority
<< VLAN_PRI_SHIFT
;
2133 evh
->vlan_tag
= hton16(vlan_tag
);
2136 } else if (eh
->ether_type
== hton16(ETHER_TYPE_IP
)) {
2137 uint8
*ip_body
= pktdata
+ sizeof(struct ether_header
);
2138 uint8 tos_tc
= IP_TOS46(ip_body
);
2139 priority
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
2143 ASSERT(priority
>= 0 && priority
<= MAXPRIO
);
2144 PKTSETPRIO(pkt
, priority
);
2145 return (rc
| priority
);
2148 #ifndef BCM_BOOTLOADER
2150 static char bcm_undeferrstr
[32];
2151 static const char *const bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
2153 /* Convert the error codes into related error strings */
2155 bcmerrorstr(int bcmerror
)
2157 /* check if someone added a bcmerror code but forgot to add errorstring */
2158 ASSERT(ABS(BCME_LAST
) == (ARRAYSIZE(bcmerrorstrtable
) - 1));
2160 if (bcmerror
> 0 || bcmerror
< BCME_LAST
) {
2161 snprintf(bcm_undeferrstr
, sizeof(bcm_undeferrstr
), "Undefined error %d", bcmerror
);
2162 return bcm_undeferrstr
;
2165 ASSERT(strlen(bcmerrorstrtable
[-bcmerror
]) < BCME_STRLEN
);
2167 return bcmerrorstrtable
[-bcmerror
];
2170 #endif /* !BCM_BOOTLOADER */
2174 BCMINITFN(bcm_nvram_refresh
)(char *flash
)
2179 ASSERT(flash
!= NULL
);
2181 /* default "empty" vars cache */
2184 if ((ret
= nvram_getall(flash
, MAX_NVRAM_SPACE
)))
2187 /* determine nvram length */
2188 for (i
= 0; i
< MAX_NVRAM_SPACE
; i
++) {
2189 if (flash
[i
] == '\0' && flash
[i
+1] == '\0')
2200 bcm_nvram_vars(uint
*length
)
2203 /* cache may be stale if nvram is read/write */
2205 ASSERT(!bcmreclaimed
);
2206 bcm_nvram_refresh(nvram_vars
);
2214 /* copy nvram vars into locally-allocated multi-string array */
2216 BCMINITFN(bcm_nvram_cache
)(void *sih
)
2222 if (vars_len
>= 0) {
2224 bcm_nvram_refresh(nvram_vars
);
2229 osh
= si_osh((si_t
*)sih
);
2231 /* allocate memory and read in flash */
2232 if (!(flash
= MALLOC(osh
, MAX_NVRAM_SPACE
))) {
2237 bcm_nvram_refresh(flash
);
2241 /* copy into a properly-sized buffer */
2242 if (!(nvram_vars
= MALLOC(osh
, vars_len
))) {
2245 bcopy(flash
, nvram_vars
, vars_len
);
2247 MFREE(osh
, flash
, MAX_NVRAM_SPACE
);
2249 /* cache must be full size of nvram if read/write */
2251 #endif /* BCMNVRAMR */
2256 #endif /* WLC_LOW */
2259 /* iovar table lookup */
2261 bcm_iovar_lookup(const bcm_iovar_t
*table
, const char *name
)
2263 const bcm_iovar_t
*vi
;
2264 const char *lookup_name
;
2266 /* skip any ':' delimited option prefixes */
2267 lookup_name
= strrchr(name
, ':');
2268 if (lookup_name
!= NULL
)
2273 ASSERT(table
!= NULL
);
2275 for (vi
= table
; vi
->name
; vi
++) {
2276 if (!strcmp(vi
->name
, lookup_name
))
2279 /* ran to end of table */
2281 return NULL
; /* var name not found */
2285 bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
2289 /* length check on io buf */
2298 /* all integers are int32 sized args at the ioctl interface */
2299 if (len
< (int)sizeof(int)) {
2300 bcmerror
= BCME_BUFTOOSHORT
;
2305 /* buffer must meet minimum length requirement */
2306 if (len
< vi
->minlen
) {
2307 bcmerror
= BCME_BUFTOOSHORT
;
2313 /* Cannot return nil... */
2314 bcmerror
= BCME_UNSUPPORTED
;
2316 /* Set is an action w/o parameters */
2317 bcmerror
= BCME_BUFTOOLONG
;
2322 /* unknown type for length check in iovar info */
2324 bcmerror
= BCME_UNSUPPORTED
;
2330 #endif /* BCMDRIVER */
2333 /*******************************************************************************
2336 * Computes a crc8 over the input data using the polynomial:
2338 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
2340 * The caller provides the initial value (either CRC8_INIT_VALUE
2341 * or the previous returned value) to allow for processing of
2342 * discontiguous blocks of data. When generating the CRC the
2343 * caller is responsible for complementing the final return value
2344 * and inserting it into the byte stream. When checking, a final
2345 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
2347 * Reference: Dallas Semiconductor Application Note 27
2348 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2349 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2350 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2352 * ****************************************************************************
2355 static const uint8 crc8_table
[256] = {
2356 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
2357 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
2358 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
2359 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
2360 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
2361 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
2362 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
2363 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
2364 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
2365 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
2366 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
2367 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
2368 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
2369 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
2370 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
2371 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
2372 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
2373 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
2374 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
2375 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
2376 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
2377 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
2378 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
2379 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
2380 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
2381 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
2382 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
2383 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
2384 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
2385 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
2386 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
2387 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
2390 #define CRC_INNER_LOOP(n, c, x) \
2391 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
2395 uint8
*pdata
, /* pointer to array of data to process */
2396 uint nbytes
, /* number of input data bytes to process */
2397 uint8 crc
/* either CRC8_INIT_VALUE or previous return value */
2400 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
2401 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
2403 while (nbytes
-- > 0)
2404 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
2409 /*******************************************************************************
2412 * Computes a crc16 over the input data using the polynomial:
2414 * x^16 + x^12 +x^5 + 1
2416 * The caller provides the initial value (either CRC16_INIT_VALUE
2417 * or the previous returned value) to allow for processing of
2418 * discontiguous blocks of data. When generating the CRC the
2419 * caller is responsible for complementing the final return value
2420 * and inserting it into the byte stream. When checking, a final
2421 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
2423 * Reference: Dallas Semiconductor Application Note 27
2424 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2425 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2426 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2428 * ****************************************************************************
2431 static const uint16 crc16_table
[256] = {
2432 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
2433 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
2434 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
2435 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
2436 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
2437 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
2438 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
2439 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
2440 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
2441 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
2442 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
2443 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
2444 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
2445 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
2446 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
2447 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
2448 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
2449 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
2450 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
2451 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
2452 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
2453 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
2454 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
2455 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
2456 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
2457 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
2458 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
2459 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
2460 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
2461 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
2462 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
2463 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
2468 uint8
*pdata
, /* pointer to array of data to process */
2469 uint nbytes
, /* number of input data bytes to process */
2470 uint16 crc
/* either CRC16_INIT_VALUE or previous return value */
2473 while (nbytes
-- > 0)
2474 CRC_INNER_LOOP(16, crc
, *pdata
++);
2478 static const uint32 crc32_table
[256] = {
2479 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
2480 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
2481 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
2482 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
2483 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
2484 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
2485 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
2486 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
2487 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
2488 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
2489 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
2490 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
2491 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
2492 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
2493 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
2494 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
2495 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
2496 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
2497 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
2498 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
2499 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
2500 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
2501 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
2502 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
2503 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
2504 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
2505 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
2506 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
2507 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
2508 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
2509 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
2510 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
2511 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
2512 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
2513 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
2514 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
2515 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
2516 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
2517 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
2518 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
2519 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
2520 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
2521 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
2522 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
2523 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
2524 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
2525 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
2526 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
2527 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
2528 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
2529 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
2530 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
2531 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
2532 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
2533 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
2534 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
2535 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
2536 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
2537 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
2538 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
2539 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
2540 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
2541 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
2542 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
2546 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
2547 * accumulating over multiple pieces.
2550 BCMROMFN(hndcrc32
)(uint8
*pdata
, uint nbytes
, uint32 crc
)
2555 ulong
*tptr
= (ulong
*)tmp
;
2558 /* in case the beginning of the buffer isn't aligned */
2559 pend
= (uint8
*)((uint
)(pdata
+ 3) & ~0x3);
2560 nbytes
-= (pend
- pdata
);
2561 while (pdata
< pend
)
2562 CRC_INNER_LOOP(32, crc
, *pdata
++);
2566 /* handle bulk of data as 32-bit words */
2567 pend
= pdata
+ (nbytes
& ~0x3);
2568 while (pdata
< pend
) {
2569 *tptr
= *(ulong
*)pdata
;
2570 pdata
+= sizeof(ulong
*);
2571 CRC_INNER_LOOP(32, crc
, tmp
[0]);
2572 CRC_INNER_LOOP(32, crc
, tmp
[1]);
2573 CRC_INNER_LOOP(32, crc
, tmp
[2]);
2574 CRC_INNER_LOOP(32, crc
, tmp
[3]);
2578 /* 1-3 bytes at end of buffer */
2579 pend
= pdata
+ (nbytes
& 0x03);
2580 while (pdata
< pend
)
2581 CRC_INNER_LOOP(32, crc
, *pdata
++);
2583 pend
= pdata
+ nbytes
;
2584 while (pdata
< pend
)
2585 CRC_INNER_LOOP(32, crc
, *pdata
++);
2586 #endif /* __mips__ */
2592 #define CLEN 1499 /* CRC Length */
2593 #define CBUFSIZ (CLEN+4)
2594 #define CNBUFS 5 /* # of bufs */
2603 uint32 crc32tv
[CNBUFS
] =
2604 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
2606 ASSERT((buf
= MALLOC(CBUFSIZ
*CNBUFS
)) != NULL
);
2608 /* step through all possible alignments */
2609 for (l
= 0; l
<= 4; l
++) {
2610 for (j
= 0; j
< CNBUFS
; j
++) {
2612 for (k
= 0; k
< len
[j
]; k
++)
2613 *(buf
+ j
*CBUFSIZ
+ (k
+l
)) = (j
+k
) & 0xff;
2616 for (j
= 0; j
< CNBUFS
; j
++) {
2617 crcr
= crc32(buf
+ j
*CBUFSIZ
+ l
, len
[j
], CRC32_INIT_VALUE
);
2618 ASSERT(crcr
== crc32tv
[j
]);
2622 MFREE(buf
, CBUFSIZ
*CNBUFS
);
2628 * Advance from the current 1-byte tag/1-byte length/variable-length value
2629 * triple, to the next, returning a pointer to the next.
2630 * If the current or next TLV is invalid (does not fit in given buffer length),
2632 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
2633 * by the TLV parameter's length if it is valid.
2636 BCMROMFN(bcm_next_tlv
)(bcm_tlv_t
*elt
, int *buflen
)
2640 /* validate current elt */
2641 if (!bcm_valid_tlv(elt
, *buflen
))
2644 /* advance to next elt */
2646 elt
= (bcm_tlv_t
*)(elt
->data
+ len
);
2647 *buflen
-= (TLV_HDR_LEN
+ len
);
2649 /* validate next elt */
2650 if (!bcm_valid_tlv(elt
, *buflen
))
2657 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2658 * triples, returning a pointer to the substring whose first element
2662 BCMROMFN(bcm_parse_tlvs
)(void *buf
, int buflen
, uint key
)
2667 elt
= (bcm_tlv_t
*)buf
;
2670 /* find tagged parameter */
2671 while (totlen
>= TLV_HDR_LEN
) {
2674 /* validate remaining totlen */
2675 if ((elt
->id
== key
) &&
2676 (totlen
>= (len
+ TLV_HDR_LEN
)))
2679 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2680 totlen
-= (len
+ TLV_HDR_LEN
);
2687 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2688 * triples, returning a pointer to the substring whose first element
2689 * matches tag. Stop parsing when we see an element whose ID is greater
2690 * than the target key.
2693 BCMROMFN(bcm_parse_ordered_tlvs
)(void *buf
, int buflen
, uint key
)
2698 elt
= (bcm_tlv_t
*)buf
;
2701 /* find tagged parameter */
2702 while (totlen
>= TLV_HDR_LEN
) {
2706 /* Punt if we start seeing IDs > than target key */
2710 /* validate remaining totlen */
2712 (totlen
>= (len
+ TLV_HDR_LEN
)))
2715 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2716 totlen
-= (len
+ TLV_HDR_LEN
);
2721 #if defined(BCMDBG) || defined(BCMDBG_ERR) || defined(WLMSG_PRHDRS) || \
2722 defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || defined(DHD_DEBUG)
2724 bcm_format_field(const bcm_bit_desc_ex_t
*bd
, uint32 flags
, char* buf
, int len
)
2730 if (len
< 2 || !buf
)
2735 for (i
= 0; (name
= bd
->bitfield
[i
].name
) != NULL
; i
++) {
2736 bit
= bd
->bitfield
[i
].bit
;
2737 if ((flags
& mask
) == bit
) {
2738 if (len
> (int)strlen(name
)) {
2739 slen
= strlen(name
);
2740 strncpy(buf
, name
, slen
+1);
2749 bcm_format_flags(const bcm_bit_desc_t
*bd
, uint32 flags
, char* buf
, int len
)
2754 int slen
= 0, nlen
= 0;
2758 if (len
< 2 || !buf
)
2763 for (i
= 0; flags
!= 0; i
++) {
2766 if (bit
== 0 && flags
!= 0) {
2767 /* print any unnamed bits */
2768 snprintf(hexstr
, 16, "0x%X", flags
);
2770 flags
= 0; /* exit loop */
2771 } else if ((flags
& bit
) == 0)
2774 nlen
= strlen(name
);
2776 /* count btwn flag space */
2779 /* need NULL char as well */
2782 /* copy NULL char but don't count it */
2783 strncpy(p
, name
, nlen
+ 1);
2785 /* copy btwn flag space and NULL char */
2787 p
+= snprintf(p
, 2, " ");
2790 /* indicate the str was too short */
2793 p
-= 2 - len
; /* overwrite last char */
2794 p
+= snprintf(p
, 2, ">");
2797 return (int)(p
- buf
);
2800 /* print bytes formatted as hex to a string. return the resulting string length */
2802 bcm_format_hex(char *str
, const void *bytes
, int len
)
2806 const uint8
*src
= (const uint8
*)bytes
;
2808 for (i
= 0; i
< len
; i
++) {
2809 p
+= snprintf(p
, 3, "%02X", *src
);
2812 return (int)(p
- str
);
2816 /* pretty hex print a contiguous buffer */
2818 prhex(const char *msg
, uchar
*buf
, uint nbytes
)
2821 int len
= sizeof(line
);
2825 if (msg
&& (msg
[0] != '\0'))
2826 printf("%s:\n", msg
);
2829 for (i
= 0; i
< nbytes
; i
++) {
2831 nchar
= snprintf(p
, len
, " %04d: ", i
); /* line prefix */
2836 nchar
= snprintf(p
, len
, "%02x ", buf
[i
]);
2842 printf("%s\n", line
); /* flush line */
2848 /* flush last partial line */
2850 printf("%s\n", line
);
2853 static const char *crypto_algo_names
[] = {
2869 bcm_crypto_algo_name(uint algo
)
2871 return (algo
< ARRAYSIZE(crypto_algo_names
)) ? crypto_algo_names
[algo
] : "ERR";
2876 deadbeef(void *p
, uint len
)
2878 static uint8 meat
[] = { 0xde, 0xad, 0xbe, 0xef };
2881 *(uint8
*)p
= meat
[((uintptr
)p
) & 3];
2888 bcm_chipname(uint chipid
, char *buf
, uint len
)
2892 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
2893 snprintf(buf
, len
, fmt
, chipid
);
2897 /* Produce a human-readable string for boardrev */
2899 bcm_brev_str(uint32 brev
, char *buf
)
2902 snprintf(buf
, 8, "%d.%d", (brev
& 0xf0) >> 4, brev
& 0xf);
2904 snprintf(buf
, 8, "%c%03x", ((brev
& 0xf000) == 0x1000) ? 'P' : 'A', brev
& 0xfff);
2909 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2911 /* dump large strings to console */
2920 max_len
= BUFSIZE_TODUMP_ATONCE
;
2922 while (len
> max_len
) {
2924 buf
[max_len
] = '\0';
2931 /* print the remaining string */
2932 printf("%s\n", buf
);
2936 /* routine to dump fields in a fileddesc structure */
2938 bcmdumpfields(bcmutl_rdreg_rtn read_rtn
, void *arg0
, uint arg1
, struct fielddesc
*fielddesc_array
,
2939 char *buf
, uint32 bufsize
)
2943 struct fielddesc
*cur_ptr
;
2946 cur_ptr
= fielddesc_array
;
2948 while (bufsize
> 1) {
2949 if (cur_ptr
->nameandfmt
== NULL
)
2951 len
= snprintf(buf
, bufsize
, cur_ptr
->nameandfmt
,
2952 read_rtn(arg0
, arg1
, cur_ptr
->offset
));
2953 /* check for snprintf overflow or error */
2954 if (len
< 0 || (uint32
)len
>= bufsize
)
2965 bcm_mkiovar(char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
2969 len
= strlen(name
) + 1;
2971 if ((len
+ datalen
) > buflen
)
2974 strncpy(buf
, name
, buflen
);
2976 /* append data onto the end of the name string */
2977 memcpy(&buf
[len
], data
, datalen
);
2983 /* Quarter dBm units to mW
2984 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
2985 * Table is offset so the last entry is largest mW value that fits in
2989 #define QDBM_OFFSET 153 /* Offset for first entry */
2990 #define QDBM_TABLE_LEN 40 /* Table size */
2992 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
2993 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
2995 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
2997 /* Largest mW value that will round down to the last table entry,
2998 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
2999 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
3001 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
3003 static const uint16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
3004 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
3005 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
3006 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
3007 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
3008 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
3009 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
3013 BCMROMFN(bcm_qdbm_to_mw
)(uint8 qdbm
)
3016 int idx
= qdbm
- QDBM_OFFSET
;
3018 if (idx
>= QDBM_TABLE_LEN
) {
3019 /* clamp to max uint16 mW value */
3023 /* scale the qdBm index up to the range of the table 0-40
3024 * where an offset of 40 qdBm equals a factor of 10 mW.
3031 /* return the mW value scaled down to the correct factor of 10,
3032 * adding in factor/2 to get proper rounding.
3034 return ((nqdBm_to_mW_map
[idx
] + factor
/2) / factor
);
3038 BCMROMFN(bcm_mw_to_qdbm
)(uint16 mw
)
3045 /* handle boundary case */
3049 offset
= QDBM_OFFSET
;
3051 /* move mw into the range of the table */
3052 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
3057 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
-1; qdbm
++) {
3058 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+1] -
3059 nqdBm_to_mW_map
[qdbm
])/2;
3060 if (mw_uint
< boundary
) break;
3063 qdbm
+= (uint8
)offset
;
3070 BCMROMFN(bcm_bitcount
)(uint8
*bitmap
, uint length
)
3072 uint bitcount
= 0, i
;
3074 for (i
= 0; i
< length
; i
++) {
3086 /* Initialization of bcmstrbuf structure */
3088 bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
3090 b
->origsize
= b
->size
= size
;
3091 b
->origbuf
= b
->buf
= buf
;
3094 /* Buffer sprintf wrapper to guard against buffer overflow */
3096 bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
3103 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
3105 /* Non Ansi C99 compliant returns -1,
3106 * Ansi compliant return r >= b->size,
3107 * bcmstdlib returns 0, handle all
3109 /* r == 0 is also the case when strlen(fmt) is zero.
3110 * typically the case when "" is passed as argument.
3112 if ((r
== -1) || (r
>= (int)b
->size
)) {
3125 bcm_bprhex(struct bcmstrbuf
*b
, const char *msg
, bool newline
, uint8
*buf
, int len
)
3129 if (msg
!= NULL
&& msg
[0] != '\0')
3130 bcm_bprintf(b
, "%s", msg
);
3131 for (i
= 0; i
< len
; i
++)
3132 bcm_bprintf(b
, "%02X", buf
[i
]);
3134 bcm_bprintf(b
, "\n");
3138 bcm_inc_bytes(uchar
*num
, int num_bytes
, uint8 amount
)
3142 for (i
= 0; i
< num_bytes
; i
++) {
3144 if (num
[i
] >= amount
)
3151 bcm_cmp_bytes(const uchar
*arg1
, const uchar
*arg2
, uint8 nbytes
)
3155 for (i
= nbytes
- 1; i
>= 0; i
--) {
3156 if (arg1
[i
] != arg2
[i
])
3157 return (arg1
[i
] - arg2
[i
]);
3163 bcm_print_bytes(const char *name
, const uchar
*data
, int len
)
3168 printf("%s: %d \n", name
? name
: "", len
);
3169 for (i
= 0; i
< len
; i
++) {
3170 printf("%02x ", *data
++);
3172 if (per_line
== 16) {
3179 #if defined(WLTINYDUMP) || defined(BCMDBG) || defined(WLMSG_INFORM) || \
3180 defined(WLMSG_ASSOC) || defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
3181 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
3184 bcm_format_ssid(char* buf
, const uchar ssid
[], uint ssid_len
)
3188 char *endp
= buf
+ SSID_FMT_BUF_LEN
;
3190 if (ssid_len
> DOT11_MAX_SSID_LEN
) ssid_len
= DOT11_MAX_SSID_LEN
;
3192 for (i
= 0; i
< ssid_len
; i
++) {
3197 } else if (bcm_isprint((uchar
)c
)) {
3200 p
+= snprintf(p
, (endp
- p
), "\\x%02X", c
);
3206 return (int)(p
- buf
);
3208 #endif /* WLTINYDUMP || BCMDBG || WLMSG_INFORM || WLMSG_ASSOC || WLMSG_PRPKT */
3210 #endif /* BCMDRIVER */
3213 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
3214 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
3215 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
3216 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
3220 process_nvram_vars(char *varbuf
, unsigned int len
)
3225 unsigned int buf_len
, n
;
3226 unsigned int pad
= 0;
3230 findNewline
= FALSE
;
3233 for (n
= 0; n
< len
; n
++) {
3234 if (varbuf
[n
] == '\r')
3236 if (findNewline
&& varbuf
[n
] != '\n')
3238 findNewline
= FALSE
;
3239 if (varbuf
[n
] == '#') {
3243 if (varbuf
[n
] == '\n') {
3253 buf_len
= (unsigned int)(dp
- varbuf
);
3255 pad
= 4 - buf_len
% 4;
3256 if (pad
&& (buf_len
+ pad
<= len
)) {
3261 while (dp
< varbuf
+ n
)
3267 /* calculate a * b + c */
3269 bcm_uint64_multiple_add(uint32
* r_high
, uint32
* r_low
, uint32 a
, uint32 b
, uint32 c
)
3271 #define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
3273 uint32 a1
, a0
, b1
, b0
, t
, cc
= 0;
3283 t
= (a1
* b0
) << 16;
3289 t
= (a0
* b1
) << 16;
3300 r0
|= (cc
% 2) ? 0x80000000 : 0;
3301 r1
= a1
* b1
+ ((a1
* b0
) >> 16) + ((b1
* a0
) >> 16) + (cc
/ 2);
3307 /* calculate a / b */
3309 bcm_uint64_divide(uint32
* r
, uint32 a_high
, uint32 a_low
, uint32 b
)
3311 uint32 a1
= a_high
, a0
= a_low
, r0
= 0;
3317 r0
+= (0xffffffff / b
) * a1
;
3318 bcm_uint64_multiple_add(&a1
, &a0
, ((0xffffffff % b
) + 1) % b
, a1
, a0
);
3325 /* calculate a >> b; and returns only lower 32 bits */
3327 bcm_uint64_right_shift(uint32
* r
, uint32 a_high
, uint32 a_low
, uint32 b
)
3329 uint32 a1
= a_high
, a0
= a_low
, r0
= 0;
3339 a1
= a1
& ((1 << b
) - 1);
3340 a1
= a1
<< (32 - b
);
3345 r0
= a1
>> (b
- 32);