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.
20 #include <bcmendian.h>
22 #include "proto/ethernet.h"
23 #include "proto/vlan.h"
24 #include "proto/bcmip.h"
25 #include "proto/bcmtcp.h"
26 #include "proto/802.1d.h"
33 /* nvram vars cache */
34 static char *nvram_vars
= NULL
;
35 static int vars_len
= -1;
38 /* copy a pkt buffer chain into a buffer */
40 pktcopy (osl_t
* osh
, void *p
, uint offset
, int len
, uchar
* buf
)
45 len
= 4096; /* "infinite" */
47 /* skip 'offset' bytes */
48 for (; p
&& offset
; p
= PKTNEXT (osh
, p
))
50 if (offset
< (uint
) PKTLEN (osh
, p
))
52 offset
-= PKTLEN (osh
, p
);
59 for (; p
&& len
; p
= PKTNEXT (osh
, p
))
61 n
= MIN ((uint
) PKTLEN (osh
, p
) - offset
, (uint
) len
);
62 bcopy (PKTDATA (osh
, p
) + offset
, buf
, n
);
72 /* return total length of buffer chain */
74 pkttotlen (osl_t
* osh
, void *p
)
79 for (; p
; p
= PKTNEXT (osh
, p
))
80 total
+= PKTLEN (osh
, p
);
84 /* return the last buffer of chained pkt */
86 pktlast (osl_t
* osh
, void *p
)
88 for (; PKTNEXT (osh
, p
); p
= PKTNEXT (osh
, p
))
96 * osl multiple-precedence packet queue
97 * hi_prec is always >= the number of the highest non-empty precedence
100 pktq_penq (struct pktq
*pq
, int prec
, void *p
)
104 ASSERT (prec
>= 0 && prec
< pq
->num_prec
);
105 ASSERT (PKTLINK (p
) == NULL
); /* queueing chains not allowed */
107 ASSERT (!pktq_full (pq
));
108 ASSERT (!pktq_pfull (pq
, prec
));
113 PKTSETLINK (q
->tail
, p
);
122 if (pq
->hi_prec
< prec
)
123 pq
->hi_prec
= (uint8
) prec
;
129 pktq_penq_head (struct pktq
*pq
, int prec
, void *p
)
133 ASSERT (prec
>= 0 && prec
< pq
->num_prec
);
134 ASSERT (PKTLINK (p
) == NULL
); /* queueing chains not allowed */
136 ASSERT (!pktq_full (pq
));
137 ASSERT (!pktq_pfull (pq
, prec
));
144 PKTSETLINK (p
, q
->head
);
150 if (pq
->hi_prec
< prec
)
151 pq
->hi_prec
= (uint8
) prec
;
157 pktq_pdeq (struct pktq
*pq
, int prec
)
162 ASSERT (prec
>= 0 && prec
< pq
->num_prec
);
166 if ((p
= q
->head
) == NULL
)
169 if ((q
->head
= PKTLINK (p
)) == NULL
)
176 PKTSETLINK (p
, NULL
);
182 pktq_pdeq_tail (struct pktq
*pq
, int prec
)
187 ASSERT (prec
>= 0 && prec
< pq
->num_prec
);
191 if ((p
= q
->head
) == NULL
)
194 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK (p
))
198 PKTSETLINK (prev
, NULL
);
211 pktq_pflush (osl_t
* osh
, struct pktq
*pq
, int prec
, bool dir
)
220 q
->head
= PKTLINK (p
);
221 PKTSETLINK (p
, NULL
);
222 PKTFREE (osh
, p
, dir
);
227 ASSERT (q
->len
== 0);
233 pktq_pdel (struct pktq
*pq
, void *pktbuf
, int prec
)
238 ASSERT (prec
>= 0 && prec
< pq
->num_prec
);
245 if (q
->head
== pktbuf
)
247 if ((q
->head
= PKTLINK (pktbuf
)) == NULL
)
252 for (p
= q
->head
; p
&& PKTLINK (p
) != pktbuf
; p
= PKTLINK (p
))
257 PKTSETLINK (p
, PKTLINK (pktbuf
));
258 if (q
->tail
== pktbuf
)
264 PKTSETLINK (pktbuf
, NULL
);
270 pktq_init (struct pktq
*pq
, int num_prec
, int max_len
)
274 ASSERT (num_prec
> 0 && num_prec
<= PKTQ_MAX_PREC
);
276 /* pq is variable size; only zero out what's requested */
278 OFFSETOF (struct pktq
, q
) + (sizeof (struct pktq_prec
) * num_prec
));
280 pq
->num_prec
= (uint16
) num_prec
;
282 pq
->max
= (uint16
) max_len
;
284 for (prec
= 0; prec
< num_prec
; prec
++)
285 pq
->q
[prec
].max
= pq
->max
;
289 pktq_setmax (struct pktq
*pq
, int max_len
)
296 pq
->max
= (uint16
) max_len
;
297 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
298 pq
->q
[prec
].max
= pq
->max
;
304 pktq_deq (struct pktq
*pq
, int *prec_out
)
313 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
318 if ((p
= q
->head
) == NULL
)
321 if ((q
->head
= PKTLINK (p
)) == NULL
)
331 PKTSETLINK (p
, NULL
);
337 pktq_deq_tail (struct pktq
*pq
, int *prec_out
)
346 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
347 if (pq
->q
[prec
].head
)
352 if ((p
= q
->head
) == NULL
)
355 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK (p
))
359 PKTSETLINK (prev
, NULL
);
371 PKTSETLINK (p
, NULL
);
378 pktq_peek (struct pktq
*pq
, int *prec_out
)
385 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
391 return (pq
->q
[prec
].head
);
396 pktq_peek_tail (struct pktq
*pq
, int *prec_out
)
403 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
404 if (pq
->q
[prec
].head
)
410 return (pq
->q
[prec
].tail
);
414 pktq_flush (osl_t
* osh
, struct pktq
*pq
, bool dir
)
417 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
418 pktq_pflush (osh
, pq
, prec
, dir
);
419 ASSERT (pq
->len
== 0);
422 /* Return sum of lengths of a specific set of precedences */
424 pktq_mlen (struct pktq
*pq
, uint prec_bmp
)
430 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
431 if (prec_bmp
& (1 << prec
))
432 len
+= pq
->q
[prec
].len
;
437 /* Priority dequeue from a specific set of precedences */
439 pktq_mdeq (struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
448 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
451 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
457 if ((p
= q
->head
) == NULL
)
460 if ((q
->head
= PKTLINK (p
)) == NULL
)
470 PKTSETLINK (p
, NULL
);
475 const unsigned char bcm_ctype
[] = {
476 _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, /* 0-7 */
477 _BCM_C
, _BCM_C
| _BCM_S
, _BCM_C
| _BCM_S
, _BCM_C
| _BCM_S
, _BCM_C
| _BCM_S
,
478 _BCM_C
| _BCM_S
, _BCM_C
,
480 _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, /* 16-23 */
481 _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, _BCM_C
, /* 24-31 */
482 _BCM_S
| _BCM_SP
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 32-39 */
483 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 40-47 */
484 _BCM_D
, _BCM_D
, _BCM_D
, _BCM_D
, _BCM_D
, _BCM_D
, _BCM_D
, _BCM_D
, /* 48-55 */
485 _BCM_D
, _BCM_D
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 56-63 */
486 _BCM_P
, _BCM_U
| _BCM_X
, _BCM_U
| _BCM_X
, _BCM_U
| _BCM_X
, _BCM_U
| _BCM_X
,
488 _BCM_U
| _BCM_X
, _BCM_U
, /* 64-71 */
489 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, /* 72-79 */
490 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, /* 80-87 */
491 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 88-95 */
492 _BCM_P
, _BCM_L
| _BCM_X
, _BCM_L
| _BCM_X
, _BCM_L
| _BCM_X
, _BCM_L
| _BCM_X
,
494 _BCM_L
| _BCM_X
, _BCM_L
, /* 96-103 */
495 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, /* 104-111 */
496 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, /* 112-119 */
497 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_C
, /* 120-127 */
498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
499 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
500 _BCM_S
| _BCM_SP
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
502 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 160-175 */
503 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
505 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 176-191 */
506 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
,
508 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, /* 192-207 */
509 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_P
, _BCM_U
,
511 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_L
, /* 208-223 */
512 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
,
514 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, /* 224-239 */
515 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_P
, _BCM_L
,
517 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
/* 240-255 */
520 ulong
BCMROMFN (bcm_strtoul
) (char *cp
, char **endp
, uint base
)
527 while (bcm_isspace (*cp
))
532 else if (cp
[0] == '-')
542 if ((cp
[1] == 'x') || (cp
[1] == 'X'))
556 else if (base
== 16 && (cp
[0] == '0') && ((cp
[1] == 'x') || (cp
[1] == 'X')))
563 while (bcm_isxdigit (*cp
) &&
565 bcm_isdigit (*cp
) ? *cp
- '0' : bcm_toupper (*cp
) - 'A' + 10) <
568 result
= result
* base
+ value
;
573 result
= (ulong
) (result
* -1);
582 int BCMROMFN (bcm_atoi
) (char *s
)
584 return (int) bcm_strtoul (s
, NULL
, 10);
587 /* return pointer to location of substring 'needle' in 'haystack' */
588 char *BCMROMFN (bcmstrstr
) (char *haystack
, char *needle
)
593 if ((haystack
== NULL
) || (needle
== NULL
))
596 nlen
= strlen (needle
);
597 len
= strlen (haystack
) - nlen
+ 1;
599 for (i
= 0; i
< len
; i
++)
600 if (memcmp (needle
, &haystack
[i
], nlen
) == 0)
601 return (&haystack
[i
]);
605 char *BCMROMFN (bcmstrcat
) (char *dest
, const char *src
)
607 strcpy (&dest
[strlen (dest
)], src
);
611 char *BCMROMFN (bcmstrncat
) (char *dest
, const char *src
, uint size
)
616 p
= dest
+ strlen (dest
);
619 while (p
!= endp
&& (*p
++ = *src
++) != '\0')
626 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
627 int BCMROMFN (bcm_ether_atoe
) (char *p
, struct ether_addr
* ea
)
633 ea
->octet
[i
++] = (char) bcm_strtoul (p
, &p
, 16);
641 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
642 /* registry routine buffer preparation utility functions:
643 * parameter order is like strncpy, but returns count
644 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
647 wchar2ascii (char *abuf
, ushort
* wbuf
, ushort wbuflen
, ulong abuflen
)
655 /* wbuflen is in bytes */
656 wbuflen
/= sizeof (ushort
);
658 for (i
= 0; i
< wbuflen
; ++i
)
662 *abuf
++ = (char) *wbuf
++;
669 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
673 bcm_ether_ntoa (struct ether_addr
*ea
, char *buf
)
675 snprintf (buf
, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
676 ea
->octet
[0] & 0xff, ea
->octet
[1] & 0xff, ea
->octet
[2] & 0xff,
677 ea
->octet
[3] & 0xff, ea
->octet
[4] & 0xff, ea
->octet
[5] & 0xff);
682 bcm_ip_ntoa (struct ipv4_addr
*ia
, char *buf
)
684 snprintf (buf
, 16, "%d.%d.%d.%d",
685 ia
->addr
[0], ia
->addr
[1], ia
->addr
[2], ia
->addr
[3]);
693 for (i
= 0; i
< ms
; i
++)
703 * Search the name=value vars for a specific one and return its value.
704 * Returns NULL if not found.
707 getvar (char *vars
, const char *name
)
722 /* first look in vars[] */
723 for (s
= vars
; s
&& *s
;)
726 if ((bcmp (s
, name
, len
) == 0) && (s
[len
] == '='))
727 return (&s
[len
+ 1]);
733 /* then query nvram */
734 return (nvram_get (name
));
735 #endif /* _MINOSL_ */
739 * Search the vars for a specific one and return its value as
740 * an integer. Returns 0 if not found.
743 getintvar (char *vars
, const char *name
)
750 if ((val
= getvar (vars
, name
)) == NULL
)
753 return (bcm_strtoul (val
, NULL
, 0));
754 #endif /* _MINOSL_ */
758 /* Search for token in comma separated token-string */
760 findmatch (char *string
, char *name
)
767 while ((c
= strchr (string
, ',')) != NULL
)
769 if (len
== (uint
) (c
- string
) && !strncmp (string
, name
, len
))
774 return (!strcmp (string
, name
));
777 /* Return gpio pin number assigned to the named pin
779 * Variable should be in format:
781 * gpio<N>=pin_name,pin_name
783 * This format allows multiple features to share the gpio with mutual
786 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
787 * and if def_pin is not used by others.
790 getgpiopin (char *vars
, char *pin_name
, uint def_pin
)
792 char name
[] = "gpioXXXX";
796 /* Go thru all possibilities till a match in pin name */
797 for (pin
= 0; pin
< GPIO_NUMPINS
; pin
++)
799 snprintf (name
, sizeof (name
), "gpio%d", pin
);
800 val
= getvar (vars
, name
);
801 if (val
&& findmatch (val
, pin_name
))
805 if (def_pin
!= GPIO_PIN_NOTDEFINED
)
807 /* make sure the default pin is not used by someone else */
808 snprintf (name
, sizeof (name
), "gpio%d", def_pin
);
809 if (getvar (vars
, name
))
811 def_pin
= GPIO_PIN_NOTDEFINED
;
821 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
830 /* last entry logged */
831 static uint logi
= 0;
832 /* next entry to read */
833 static uint readi
= 0;
838 BCMPERF_ENABLE_INSTRCOUNT ();
839 BCMPERF_ENABLE_ICACHE_MISS ();
840 BCMPERF_ENABLE_ICACHE_HIT ();
844 bcmlog (char *fmt
, uint a1
, uint a2
)
846 static uint last
= 0;
848 OSL_GETCYCLES (cycles
);
852 logtab
[i
].cycles
= cycles
- last
;
857 logi
= (i
+ 1) % LOGSIZE
;
865 static uint last
= 0;
866 static uint32 ic_miss
= 0;
867 static uint32 instr_count
= 0;
869 uint32 instr_count_cur
;
872 OSL_GETCYCLES (cycles
);
873 BCMPERF_GETICACHE_MISS (ic_miss_cur
);
874 BCMPERF_GETINSTRCOUNT (instr_count_cur
);
878 logtab
[i
].cycles
= cycles
- last
;
879 logtab
[i
].a1
= ic_miss_cur
- ic_miss
;
880 logtab
[i
].a2
= instr_count_cur
- instr_count
;
883 logi
= (i
+ 1) % LOGSIZE
;
886 instr_count
= instr_count_cur
;
887 ic_miss
= ic_miss_cur
;
892 bcmdumplog (char *buf
, int size
)
898 limit
= buf
+ size
- 80;
906 /* print in chronological order */
908 for (j
= 0; j
< num
&& (buf
< limit
); readi
= (readi
+ 1) % LOGSIZE
, j
++)
910 if (logtab
[readi
].fmt
== NULL
)
913 buf
+= sprintf (buf
, "%d\t", logtab
[readi
].cycles
);
915 sprintf (buf
, logtab
[readi
].fmt
, logtab
[readi
].a1
, logtab
[readi
].a2
);
916 buf
+= sprintf (buf
, "\n");
923 * Dump one log entry at a time.
924 * Return index of next entry or -1 when no more .
927 bcmdumplogent (char *buf
, uint i
)
932 * If buf is NULL, return the starting index,
933 * interpreting i as the indicator of last 'i' entries to dump.
937 i
= ((i
> 0) && (i
< (LOGSIZE
- 1))) ? i
: (LOGSIZE
- 1);
938 return ((logi
- i
) % LOGSIZE
);
943 ASSERT (i
< LOGSIZE
);
949 for (; (i
!= logi
) && !hit
; i
= (i
+ 1) % LOGSIZE
)
951 if (logtab
[i
].fmt
== NULL
)
953 buf
+= sprintf (buf
, "%d: %d\t", i
, logtab
[i
].cycles
);
954 buf
+= sprintf (buf
, logtab
[i
].fmt
, logtab
[i
].a1
, logtab
[i
].a2
);
955 buf
+= sprintf (buf
, "\n");
962 #endif /* BCMPERFSTATS */
965 /* pretty hex print a pkt buffer chain */
967 prpkt (const char *msg
, osl_t
* osh
, void *p0
)
971 if (msg
&& (msg
[0] != '\0'))
972 printf ("%s:\n", msg
);
974 for (p
= p0
; p
; p
= PKTNEXT (osh
, p
))
975 prhex (NULL
, PKTDATA (osh
, p
), PKTLEN (osh
, p
));
979 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
980 * Also updates the inplace vlan tag if requested.
981 * For debugging, it returns an indication of what it did.
984 pktsetprio (void *pkt
, bool update_vtag
)
986 struct ether_header
*eh
;
987 struct ethervlan_header
*evh
;
992 pktdata
= (uint8
*) PKTDATA (NULL
, pkt
);
993 ASSERT (ISALIGNED ((uintptr
) pktdata
, sizeof (uint16
)));
995 eh
= (struct ether_header
*) pktdata
;
997 if (ntoh16 (eh
->ether_type
) == ETHER_TYPE_8021Q
)
1000 int vlan_prio
, dscp_prio
= 0;
1002 evh
= (struct ethervlan_header
*) eh
;
1004 vlan_tag
= ntoh16 (evh
->vlan_tag
);
1005 vlan_prio
= (int) (vlan_tag
>> VLAN_PRI_SHIFT
) & VLAN_PRI_MASK
;
1007 if (ntoh16 (evh
->ether_type
) == ETHER_TYPE_IP
)
1009 uint8
*ip_body
= pktdata
+ sizeof (struct ethervlan_header
);
1010 uint8 tos_tc
= IP_TOS (ip_body
);
1011 dscp_prio
= (int) (tos_tc
>> IPV4_TOS_PREC_SHIFT
);
1012 if ((IP_VER (ip_body
) == IP_VER_4
)
1013 && (IPV4_PROT (ip_body
) == IP_PROT_TCP
))
1020 ip_len
= IPV4_PAYLOAD_LEN (ip_body
);
1021 tcp_hdr
= IPV4_NO_OPTIONS_PAYLOAD (ip_body
);
1022 src_port
= TCP_SRC_PORT (tcp_hdr
);
1023 src_port_exc
= (src_port
== 10110) || (src_port
== 10120) ||
1024 (src_port
== 10130) || (src_port
== 10140);
1026 if ((ip_len
== 40) && src_port_exc
&& TCP_IS_ACK (tcp_hdr
))
1033 /* DSCP priority gets precedence over 802.1P (vlan tag) */
1036 priority
= dscp_prio
;
1037 rc
|= PKTPRIO_VDSCP
;
1041 priority
= vlan_prio
;
1045 * If the DSCP priority is not the same as the VLAN priority,
1046 * then overwrite the priority field in the vlan tag, with the
1047 * DSCP priority value. This is required for Linux APs because
1048 * the VLAN driver on Linux, overwrites the skb->priority field
1049 * with the priority value in the vlan tag
1051 if (update_vtag
&& (priority
!= vlan_prio
))
1053 vlan_tag
&= ~(VLAN_PRI_MASK
<< VLAN_PRI_SHIFT
);
1054 vlan_tag
|= (uint16
) priority
<< VLAN_PRI_SHIFT
;
1055 evh
->vlan_tag
= hton16 (vlan_tag
);
1059 else if (ntoh16 (eh
->ether_type
) == ETHER_TYPE_IP
)
1061 uint8
*ip_body
= pktdata
+ sizeof (struct ether_header
);
1062 uint8 tos_tc
= IP_TOS (ip_body
);
1063 priority
= (int) (tos_tc
>> IPV4_TOS_PREC_SHIFT
);
1065 if ((IP_VER (ip_body
) == IP_VER_4
)
1066 && (IPV4_PROT (ip_body
) == IP_PROT_TCP
))
1073 ip_len
= IPV4_PAYLOAD_LEN (ip_body
);
1074 tcp_hdr
= IPV4_NO_OPTIONS_PAYLOAD (ip_body
);
1075 src_port
= TCP_SRC_PORT (tcp_hdr
);
1076 src_port_exc
= (src_port
== 10110) || (src_port
== 10120) ||
1077 (src_port
== 10130) || (src_port
== 10140);
1079 if ((ip_len
== 40) && src_port_exc
&& TCP_IS_ACK (tcp_hdr
))
1086 ASSERT (priority
>= 0 && priority
<= MAXPRIO
);
1087 PKTSETPRIO (pkt
, priority
);
1088 return (rc
| priority
);
1091 static char bcm_undeferrstr
[BCME_STRLEN
];
1093 static const char *bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
1095 /* Convert the error codes into related error strings */
1097 bcmerrorstr (int bcmerror
)
1099 /* check if someone added a bcmerror code but forgot to add errorstring */
1100 ASSERT (ABS (BCME_LAST
) == (ARRAYSIZE (bcmerrorstrtable
) - 1));
1102 if (bcmerror
> 0 || bcmerror
< BCME_LAST
)
1104 snprintf (bcm_undeferrstr
, BCME_STRLEN
, "Undefined error %d", bcmerror
);
1105 return bcm_undeferrstr
;
1108 ASSERT (strlen (bcmerrorstrtable
[-bcmerror
]) < BCME_STRLEN
);
1110 return bcmerrorstrtable
[-bcmerror
];
1114 static void BCMINITFN (bcm_nvram_refresh
) (char *flash
)
1121 /* default "empty" vars cache */
1124 if ((ret
= nvram_getall (flash
, NVRAM_SPACE
)))
1127 /* determine nvram length */
1128 for (i
= 0; i
< NVRAM_SPACE
; i
++)
1130 if (flash
[i
] == '\0' && flash
[i
+ 1] == '\0')
1141 #ifdef BCMDBG_PKT /* pkt logging for debugging */
1142 /* Add a packet to the pktlist */
1144 pktlist_add (pktlist_info_t
* pktlist
, void *pkt
)
1147 ASSERT (pktlist
->count
< PKTLIST_SIZE
);
1149 /* Verify the packet is not already part of the list */
1150 for (i
= 0; i
< pktlist
->count
; i
++)
1152 if (pktlist
->list
[i
] == pkt
)
1155 pktlist
->list
[pktlist
->count
] = pkt
;
1160 /* Remove a packet from the pktlist */
1162 pktlist_remove (pktlist_info_t
* pktlist
, void *pkt
)
1165 uint num
= pktlist
->count
;
1167 /* find the index where pkt exists */
1168 for (i
= 0; i
< num
; i
++)
1170 /* check for the existence of pkt in the list */
1171 if (pktlist
->list
[i
] == pkt
)
1173 /* replace with the last element */
1174 pktlist
->list
[i
] = pktlist
->list
[num
- 1];
1182 /* Dump the pktlist (and the contents of each packet if 'data'
1183 * is set). 'buf' should be large enough
1187 pktlist_dump (pktlist_info_t
* pktlist
, char *buf
)
1194 buf
+= sprintf (buf
, "Packet list dump:\n");
1196 for (i
= 0; i
< (pktlist
->count
); i
++)
1198 buf
+= sprintf (buf
, "0x%p\t", pktlist
->list
[i
]);
1200 #ifdef NOTDEF /* Remove this ifdef to print pkttag and pktdata */
1201 if (PKTTAG (pktlist
->list
[i
]))
1204 buf
+= sprintf (buf
, "Pkttag(in hex): ");
1206 bcm_format_hex (buf
, PKTTAG (pktlist
->list
[i
]), OSL_PKTTAG_SZ
);
1208 buf
+= sprintf (buf
, "Pktdata(in hex): ");
1209 buf
+= bcm_format_hex (buf
, PKTDATA (NULL
, pktlist
->list
[i
]),
1210 PKTLEN (NULL
, pktlist
->list
[i
]));
1213 buf
+= sprintf (buf
, "\n");
1217 #endif /* BCMDBG_PKT */
1220 /* iovar table lookup */
1222 bcm_iovar_lookup (const bcm_iovar_t
* table
, const char *name
)
1224 const bcm_iovar_t
*vi
;
1225 const char *lookup_name
;
1227 /* skip any ':' delimited option prefixes */
1228 lookup_name
= strrchr (name
, ':');
1229 if (lookup_name
!= NULL
)
1236 for (vi
= table
; vi
->name
; vi
++)
1238 if (!strcmp (vi
->name
, lookup_name
))
1241 /* ran to end of table */
1243 return NULL
; /* var name not found */
1248 bcm_iovar_lencheck (const bcm_iovar_t
* vi
, void *arg
, int len
, bool set
)
1252 /* length check on io buf */
1262 /* all integers are int32 sized args at the ioctl interface */
1263 if (len
< (int) sizeof (int))
1265 bcmerror
= BCME_BUFTOOSHORT
;
1270 /* buffer must meet minimum length requirement */
1271 if (len
< vi
->minlen
)
1273 bcmerror
= BCME_BUFTOOSHORT
;
1280 /* Cannot return nil... */
1281 bcmerror
= BCME_UNSUPPORTED
;
1285 /* Set is an action w/o parameters */
1286 bcmerror
= BCME_BUFTOOLONG
;
1291 /* unknown type for length check in iovar info */
1293 bcmerror
= BCME_UNSUPPORTED
;
1299 #define CRC_INNER_LOOP(n, c, x) \
1300 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1303 /*******************************************************************************
1306 * Computes a crc8 over the input data using the polynomial:
1308 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1310 * The caller provides the initial value (either CRC8_INIT_VALUE
1311 * or the previous returned value) to allow for processing of
1312 * discontiguous blocks of data. When generating the CRC the
1313 * caller is responsible for complementing the final return value
1314 * and inserting it into the byte stream. When checking, a final
1315 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1317 * Reference: Dallas Semiconductor Application Note 27
1318 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1319 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1320 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1322 * ****************************************************************************
1325 static const uint8 crc8_table
[256] = {
1326 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1327 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1328 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1329 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1330 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1331 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1332 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1333 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1334 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1335 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1336 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1337 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1338 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1339 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1340 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1341 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1342 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1343 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1344 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1345 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1346 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1347 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1348 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1349 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1350 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1351 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1352 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1353 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1354 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1355 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1356 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1357 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1360 uint8
BCMROMFN (hndcrc8
) (uint8
* pdata
, /* pointer to array of data to process */
1361 uint nbytes
, /* number of input data bytes to process */
1362 uint8 crc
/* either CRC8_INIT_VALUE or previous return value */
1365 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1366 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1368 while (nbytes
-- > 0)
1369 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
1374 /*******************************************************************************
1377 * Computes a crc16 over the input data using the polynomial:
1379 * x^16 + x^12 +x^5 + 1
1381 * The caller provides the initial value (either CRC16_INIT_VALUE
1382 * or the previous returned value) to allow for processing of
1383 * discontiguous blocks of data. When generating the CRC the
1384 * caller is responsible for complementing the final return value
1385 * and inserting it into the byte stream. When checking, a final
1386 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1388 * Reference: Dallas Semiconductor Application Note 27
1389 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1390 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1391 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1393 * ****************************************************************************
1395 static const uint16 crc16_table
[256] = {
1396 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1397 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1398 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1399 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1400 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1401 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1402 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1403 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1404 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1405 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1406 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1407 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1408 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1409 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1410 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1411 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1412 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1413 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1414 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1415 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1416 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1417 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1418 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1419 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1420 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1421 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1422 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1423 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1424 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1425 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1426 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1427 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1430 uint16
BCMROMFN (hndcrc16
) (uint8
* pdata
, /* pointer to array of data to process */
1431 uint nbytes
, /* number of input data bytes to process */
1432 uint16 crc
/* either CRC16_INIT_VALUE or previous return value */
1435 while (nbytes
-- > 0)
1436 CRC_INNER_LOOP (16, crc
, *pdata
++);
1441 static const uint32 crc32_table
[256] = {
1442 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1443 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1444 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1445 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1446 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1447 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1448 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1449 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1450 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1451 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1452 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1453 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1454 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1455 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1456 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1457 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1458 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1459 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1460 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1461 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1462 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1463 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1464 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1465 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1466 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1467 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1468 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1469 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1470 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1471 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1472 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1473 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1474 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1475 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1476 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1477 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1478 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1479 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1480 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1481 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1482 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1483 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1484 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1485 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1486 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1487 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1488 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1489 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1490 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1491 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1492 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1493 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1494 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1495 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1496 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1497 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1498 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1499 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1500 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1501 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1502 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1503 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1504 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1505 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1508 uint32
BCMROMFN (hndcrc32
) (uint8
* pdata
, /* pointer to array of data to process */
1509 uint nbytes
, /* number of input data bytes to process */
1510 uint32 crc
/* either CRC32_INIT_VALUE or previous return value */
1516 ulong
*tptr
= (ulong
*) tmp
;
1518 /* in case the beginning of the buffer isn't aligned */
1519 pend
= (uint8
*) ((uint
) (pdata
+ 3) & 0xfffffffc);
1520 nbytes
-= (pend
- pdata
);
1521 while (pdata
< pend
)
1522 CRC_INNER_LOOP (32, crc
, *pdata
++);
1524 /* handle bulk of data as 32-bit words */
1525 pend
= pdata
+ (nbytes
& 0xfffffffc);
1526 while (pdata
< pend
)
1528 *tptr
= *(ulong
*) pdata
;
1529 pdata
+= sizeof (ulong
*);
1530 CRC_INNER_LOOP (32, crc
, tmp
[0]);
1531 CRC_INNER_LOOP (32, crc
, tmp
[1]);
1532 CRC_INNER_LOOP (32, crc
, tmp
[2]);
1533 CRC_INNER_LOOP (32, crc
, tmp
[3]);
1536 /* 1-3 bytes at end of buffer */
1537 pend
= pdata
+ (nbytes
& 0x03);
1538 while (pdata
< pend
)
1539 CRC_INNER_LOOP (32, crc
, *pdata
++);
1541 pend
= pdata
+ nbytes
;
1542 while (pdata
< pend
)
1543 CRC_INNER_LOOP (32, crc
, *pdata
++);
1544 #endif /* __mips__ */
1550 #define CLEN 1499 /* CRC Length */
1551 #define CBUFSIZ (CLEN+4)
1552 #define CNBUFS 5 /* # of bufs */
1561 uint32 crc32tv
[CNBUFS
] =
1562 { 0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110 };
1564 ASSERT ((buf
= MALLOC (CBUFSIZ
* CNBUFS
)) != NULL
);
1566 /* step through all possible alignments */
1567 for (l
= 0; l
<= 4; l
++)
1569 for (j
= 0; j
< CNBUFS
; j
++)
1572 for (k
= 0; k
< len
[j
]; k
++)
1573 *(buf
+ j
* CBUFSIZ
+ (k
+ l
)) = (j
+ k
) & 0xff;
1576 for (j
= 0; j
< CNBUFS
; j
++)
1578 crcr
= crc32 (buf
+ j
* CBUFSIZ
+ l
, len
[j
], CRC32_INIT_VALUE
);
1579 ASSERT (crcr
== crc32tv
[j
]);
1583 MFREE (buf
, CBUFSIZ
* CNBUFS
);
1589 * Advance from the current 1-byte tag/1-byte length/variable-length value
1590 * triple, to the next, returning a pointer to the next.
1591 * If the current or next TLV is invalid (does not fit in given buffer length),
1593 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1594 * by the TLV parameter's length if it is valid.
1596 bcm_tlv_t
*BCMROMFN (bcm_next_tlv
) (bcm_tlv_t
* elt
, int *buflen
)
1600 /* validate current elt */
1601 if (!bcm_valid_tlv (elt
, *buflen
))
1604 /* advance to next elt */
1606 elt
= (bcm_tlv_t
*) (elt
->data
+ len
);
1607 *buflen
-= (2 + len
);
1609 /* validate next elt */
1610 if (!bcm_valid_tlv (elt
, *buflen
))
1617 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1618 * triples, returning a pointer to the substring whose first element
1621 bcm_tlv_t
*BCMROMFN (bcm_parse_tlvs
) (void *buf
, int buflen
, uint key
)
1626 elt
= (bcm_tlv_t
*) buf
;
1629 /* find tagged parameter */
1634 /* validate remaining totlen */
1635 if ((elt
->id
== key
) && (totlen
>= (len
+ 2)))
1638 elt
= (bcm_tlv_t
*) ((uint8
*) elt
+ (len
+ 2));
1639 totlen
-= (len
+ 2);
1647 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1648 * triples, returning a pointer to the substring whose first element
1649 * matches tag. Stop parsing when we see an element whose ID is greater
1650 * than the target key.
1652 bcm_tlv_t
*BCMROMFN (bcm_parse_ordered_tlvs
) (void *buf
, int buflen
, uint key
)
1657 elt
= (bcm_tlv_t
*) buf
;
1660 /* find tagged parameter */
1666 /* Punt if we start seeing IDs > than target key */
1670 /* validate remaining totlen */
1671 if ((id
== key
) && (totlen
>= (len
+ 2)))
1674 elt
= (bcm_tlv_t
*) ((uint8
*) elt
+ (len
+ 2));
1675 totlen
-= (len
+ 2);
1682 bcm_format_flags (const bcm_bit_desc_t
* bd
, uint32 flags
, char *buf
, int len
)
1691 if (len
< 2 || !buf
)
1697 for (i
= 0; flags
!= 0; i
++)
1701 if (bit
== 0 && flags
)
1703 /* print any unnamed bits */
1704 sprintf (hexstr
, "0x%X", flags
);
1706 flags
= 0; /* exit loop */
1708 else if ((flags
& bit
) == 0)
1710 slen
+= strlen (name
);
1714 p
+= sprintf (p
, " "); /* btwn flag space */
1719 slen
= 1; /* account for btwn flag space */
1722 /* indicate the str was too short */
1726 p
--; /* overwrite last char */
1727 p
+= sprintf (p
, ">");
1730 return (int) (p
- buf
);
1734 deadbeef (void *p
, uint len
)
1736 static uint8 meat
[] = { 0xde, 0xad, 0xbe, 0xef };
1740 *(uint8
*) p
= meat
[((uintptr
) p
) & 3];
1741 p
= (uint8
*) p
+ 1;
1745 /* pretty hex print a contiguous buffer */
1747 prhex (const char *msg
, uchar
* buf
, uint nbytes
)
1752 if (msg
&& (msg
[0] != '\0'))
1753 printf ("%s:\n", msg
);
1756 for (i
= 0; i
< nbytes
; i
++)
1760 p
+= sprintf (p
, " %04d: ", i
); /* line prefix */
1762 p
+= sprintf (p
, "%02x ", buf
[i
]);
1765 printf ("%s\n", line
); /* flush line */
1770 /* flush last partial line */
1772 printf ("%s\n", line
);
1775 /* print bytes formatted as hex to a string. return the resulting string length */
1777 bcm_format_hex (char *str
, const void *bytes
, int len
)
1781 const uint8
*src
= (const uint8
*) bytes
;
1783 for (i
= 0; i
< len
; i
++)
1785 p
+= sprintf (p
, "%02X", *src
);
1788 return (int) (p
- str
);
1793 /* Produce a human-readable string for boardrev */
1795 bcm_brev_str (uint16 brev
, char *buf
)
1798 snprintf (buf
, 8, "%d.%d", (brev
& 0xf0) >> 4, brev
& 0xf);
1800 snprintf (buf
, 8, "%c%03x", ((brev
& 0xf000) == 0x1000) ? 'P' : 'A',
1806 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1808 /* dump large strings to console */
1810 printfbig (char *buf
)
1817 max_len
= BUFSIZE_TODUMP_ATONCE
;
1819 while (len
> max_len
)
1822 buf
[max_len
] = '\0';
1829 /* print the remaining string */
1830 printf ("%s\n", buf
);
1834 /* routine to dump fields in a fileddesc structure */
1836 bcmdumpfields (readreg_rtn read_rtn
, void *arg0
, void *arg1
,
1837 struct fielddesc
* fielddesc_array
, char *buf
, uint32 bufsize
)
1841 struct fielddesc
*cur_ptr
;
1844 cur_ptr
= fielddesc_array
;
1848 if (cur_ptr
->nameandfmt
== NULL
)
1850 len
= snprintf (buf
, bufsize
, cur_ptr
->nameandfmt
,
1851 read_rtn (arg0
, arg1
, cur_ptr
->offset
));
1852 /* check for snprintf overflow or error */
1853 if (len
< 0 || (uint32
) len
>= bufsize
)
1865 bcm_mkiovar (char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
1869 len
= strlen (name
) + 1;
1871 if ((len
+ datalen
) > buflen
)
1874 strncpy (buf
, name
, buflen
);
1876 /* append data onto the end of the name string */
1877 memcpy (&buf
[len
], data
, datalen
);
1883 /* Quarter dBm units to mW
1884 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1885 * Table is offset so the last entry is largest mW value that fits in
1889 #define QDBM_OFFSET 153 /* Offset for first entry */
1890 #define QDBM_TABLE_LEN 40 /* Table size */
1892 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1893 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1895 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1897 /* Largest mW value that will round down to the last table entry,
1898 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1899 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1901 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1903 static const uint16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
1904 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1905 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1906 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1907 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1908 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1909 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1912 uint16
BCMROMFN (bcm_qdbm_to_mw
) (uint8 qdbm
)
1915 int idx
= qdbm
- QDBM_OFFSET
;
1917 if (idx
> QDBM_TABLE_LEN
)
1919 /* clamp to max uint16 mW value */
1923 /* scale the qdBm index up to the range of the table 0-40
1924 * where an offset of 40 qdBm equals a factor of 10 mW.
1932 /* return the mW value scaled down to the correct factor of 10,
1933 * adding in factor/2 to get proper rounding.
1935 return ((nqdBm_to_mW_map
[idx
] + factor
/ 2) / factor
);
1938 uint8
BCMROMFN (bcm_mw_to_qdbm
) (uint16 mw
)
1945 /* handle boundary case */
1949 offset
= QDBM_OFFSET
;
1951 /* move mw into the range of the table */
1952 while (mw_uint
< QDBM_TABLE_LOW_BOUND
)
1958 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
- 1; qdbm
++)
1960 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+ 1] -
1961 nqdBm_to_mW_map
[qdbm
]) / 2;
1962 if (mw_uint
< boundary
)
1966 qdbm
+= (uint8
) offset
;
1972 uint
BCMROMFN (bcm_bitcount
) (uint8
* bitmap
, uint length
)
1974 uint bitcount
= 0, i
;
1976 for (i
= 0; i
< length
; i
++)
1989 /* Initialization of bcmstrbuf structure */
1991 bcm_binit (struct bcmstrbuf
*b
, char *buf
, uint size
)
1993 b
->origsize
= b
->size
= size
;
1994 b
->origbuf
= b
->buf
= buf
;
1997 /* Buffer sprintf wrapper to guard against buffer overflow */
1999 bcm_bprintf (struct bcmstrbuf
*b
, const char *fmt
, ...)
2005 r
= vsnprintf (b
->buf
, b
->size
, fmt
, ap
);
2007 /* Non Ansi C99 compliant returns -1,
2008 * Ansi compliant return r >= b->size,
2009 * bcmstdlib returns 0, handle all
2011 if ((r
== -1) || (r
>= (int) b
->size
) || (r
== 0))
2027 bcm_ether_ntoa (struct ether_addr
*ea
, char *buf
)
2029 snprintf (buf
, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
2030 ea
->octet
[0] & 0xff, ea
->octet
[1] & 0xff, ea
->octet
[2] & 0xff,
2031 ea
->octet
[3] & 0xff, ea
->octet
[4] & 0xff, ea
->octet
[5] & 0xff);
This page took 0.132095 seconds and 5 git commands to generate.