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