1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/ctype.h>
18#include <linux/kernel.h>
19#include <linux/string.h>
20#include <bcmdefs.h>
21#include <stdarg.h>
22#include <linux/module.h>
23#include <linux/pci.h>
24#include <linux/netdevice.h>
25#include <osl.h>
26#include <bcmutils.h>
27#include <siutils.h>
28#include <bcmnvram.h>
29#include <bcmendian.h>
30#include <bcmdevs.h>
31#include <proto/ethernet.h>
32#include <proto/802.1d.h>
33#include <proto/802.11.h>
34
35
36uint pktfrombuf(struct osl_info *osh, struct sk_buff *p, uint offset, int len,
37 unsigned char *buf)
38{
39 uint n, ret = 0;
40
41
42 for (; p && offset; p = p->next) {
43 if (offset < (uint) (p->len))
44 break;
45 offset -= p->len;
46 }
47
48 if (!p)
49 return 0;
50
51
52 for (; p && len; p = p->next) {
53 n = min((uint) (p->len) - offset, (uint) len);
54 bcopy(buf, p->data + offset, n);
55 buf += n;
56 len -= n;
57 ret += n;
58 offset = 0;
59 }
60
61 return ret;
62}
63
64uint BCMFASTPATH pkttotlen(struct osl_info *osh, struct sk_buff *p)
65{
66 uint total;
67
68 total = 0;
69 for (; p; p = p->next)
70 total += p->len;
71 return total;
72}
73
74
75
76
77
78struct sk_buff *BCMFASTPATH pktq_penq(struct pktq *pq, int prec,
79 struct sk_buff *p)
80{
81 struct pktq_prec *q;
82
83 ASSERT(prec >= 0 && prec < pq->num_prec);
84 ASSERT(p->prev == NULL);
85
86 ASSERT(!pktq_full(pq));
87 ASSERT(!pktq_pfull(pq, prec));
88
89 q = &pq->q[prec];
90
91 if (q->head)
92 q->tail->prev = p;
93 else
94 q->head = p;
95
96 q->tail = p;
97 q->len++;
98
99 pq->len++;
100
101 if (pq->hi_prec < prec)
102 pq->hi_prec = (u8) prec;
103
104 return p;
105}
106
107struct sk_buff *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec,
108 struct sk_buff *p)
109{
110 struct pktq_prec *q;
111
112 ASSERT(prec >= 0 && prec < pq->num_prec);
113 ASSERT(p->prev == NULL);
114
115 ASSERT(!pktq_full(pq));
116 ASSERT(!pktq_pfull(pq, prec));
117
118 q = &pq->q[prec];
119
120 if (q->head == NULL)
121 q->tail = p;
122
123 p->prev = q->head;
124 q->head = p;
125 q->len++;
126
127 pq->len++;
128
129 if (pq->hi_prec < prec)
130 pq->hi_prec = (u8) prec;
131
132 return p;
133}
134
135struct sk_buff *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
136{
137 struct pktq_prec *q;
138 struct sk_buff *p;
139
140 ASSERT(prec >= 0 && prec < pq->num_prec);
141
142 q = &pq->q[prec];
143
144 p = q->head;
145 if (p == NULL)
146 return NULL;
147
148 q->head = p->prev;
149 if (q->head == NULL)
150 q->tail = NULL;
151
152 q->len--;
153
154 pq->len--;
155
156 p->prev = NULL;
157
158 return p;
159}
160
161struct sk_buff *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
162{
163 struct pktq_prec *q;
164 struct sk_buff *p, *prev;
165
166 ASSERT(prec >= 0 && prec < pq->num_prec);
167
168 q = &pq->q[prec];
169
170 p = q->head;
171 if (p == NULL)
172 return NULL;
173
174 for (prev = NULL; p != q->tail; p = p->prev)
175 prev = p;
176
177 if (prev)
178 prev->prev = NULL;
179 else
180 q->head = NULL;
181
182 q->tail = prev;
183 q->len--;
184
185 pq->len--;
186
187 return p;
188}
189
190#ifdef BRCM_FULLMAC
191void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir)
192{
193 struct pktq_prec *q;
194 struct sk_buff *p;
195
196 q = &pq->q[prec];
197 p = q->head;
198 while (p) {
199 q->head = p->prev;
200 p->prev = NULL;
201 pkt_buf_free_skb(osh, p, dir);
202 q->len--;
203 pq->len--;
204 p = q->head;
205 }
206 ASSERT(q->len == 0);
207 q->tail = NULL;
208}
209
210void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir)
211{
212 int prec;
213 for (prec = 0; prec < pq->num_prec; prec++)
214 pktq_pflush(osh, pq, prec, dir);
215 ASSERT(pq->len == 0);
216}
217#else
218void
219pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir,
220 ifpkt_cb_t fn, int arg)
221{
222 struct pktq_prec *q;
223 struct sk_buff *p, *prev = NULL;
224
225 q = &pq->q[prec];
226 p = q->head;
227 while (p) {
228 if (fn == NULL || (*fn) (p, arg)) {
229 bool head = (p == q->head);
230 if (head)
231 q->head = p->prev;
232 else
233 prev->prev = p->prev;
234 p->prev = NULL;
235 pkt_buf_free_skb(osh, p, dir);
236 q->len--;
237 pq->len--;
238 p = (head ? q->head : prev->prev);
239 } else {
240 prev = p;
241 p = p->prev;
242 }
243 }
244
245 if (q->head == NULL) {
246 ASSERT(q->len == 0);
247 q->tail = NULL;
248 }
249}
250
251void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir,
252 ifpkt_cb_t fn, int arg)
253{
254 int prec;
255 for (prec = 0; prec < pq->num_prec; prec++)
256 pktq_pflush(osh, pq, prec, dir, fn, arg);
257 if (fn == NULL)
258 ASSERT(pq->len == 0);
259}
260#endif
261
262void pktq_init(struct pktq *pq, int num_prec, int max_len)
263{
264 int prec;
265
266 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
267
268
269 memset(pq, 0,
270 offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
271
272 pq->num_prec = (u16) num_prec;
273
274 pq->max = (u16) max_len;
275
276 for (prec = 0; prec < num_prec; prec++)
277 pq->q[prec].max = pq->max;
278}
279
280struct sk_buff *pktq_peek_tail(struct pktq *pq, int *prec_out)
281{
282 int prec;
283
284 if (pq->len == 0)
285 return NULL;
286
287 for (prec = 0; prec < pq->hi_prec; prec++)
288 if (pq->q[prec].head)
289 break;
290
291 if (prec_out)
292 *prec_out = prec;
293
294 return pq->q[prec].tail;
295}
296
297
298int pktq_mlen(struct pktq *pq, uint prec_bmp)
299{
300 int prec, len;
301
302 len = 0;
303
304 for (prec = 0; prec <= pq->hi_prec; prec++)
305 if (prec_bmp & (1 << prec))
306 len += pq->q[prec].len;
307
308 return len;
309}
310
311struct sk_buff *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp,
312 int *prec_out)
313{
314 struct pktq_prec *q;
315 struct sk_buff *p;
316 int prec;
317
318 if (pq->len == 0)
319 return NULL;
320
321 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
322 pq->hi_prec--;
323
324 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
325 if (prec-- == 0)
326 return NULL;
327
328 q = &pq->q[prec];
329
330 p = q->head;
331 if (p == NULL)
332 return NULL;
333
334 q->head = p->prev;
335 if (q->head == NULL)
336 q->tail = NULL;
337
338 q->len--;
339
340 if (prec_out)
341 *prec_out = prec;
342
343 pq->len--;
344
345 p->prev = NULL;
346
347 return p;
348}
349
350
351int bcm_ether_atoe(char *p, struct ether_addr *ea)
352{
353 int i = 0;
354
355 for (;;) {
356 ea->octet[i++] = (char)simple_strtoul(p, &p, 16);
357 if (!*p++ || i == 6)
358 break;
359 }
360
361 return i == 6;
362}
363
364
365
366
367
368char *getvar(char *vars, const char *name)
369{
370 char *s;
371 int len;
372
373 if (!name)
374 return NULL;
375
376 len = strlen(name);
377 if (len == 0)
378 return NULL;
379
380
381 for (s = vars; s && *s;) {
382 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
383 return &s[len + 1];
384
385 while (*s++)
386 ;
387 }
388#ifdef BRCM_FULLMAC
389 return NULL;
390#else
391
392 return nvram_get(name);
393#endif
394}
395
396
397
398
399
400int getintvar(char *vars, const char *name)
401{
402 char *val;
403
404 val = getvar(vars, name);
405 if (val == NULL)
406 return 0;
407
408 return simple_strtoul(val, NULL, 0);
409}
410
411#if defined(BCMDBG)
412
413void prpkt(const char *msg, struct osl_info *osh, struct sk_buff *p0)
414{
415 struct sk_buff *p;
416
417 if (msg && (msg[0] != '\0'))
418 printf("%s:\n", msg);
419
420 for (p = p0; p; p = p->next)
421 prhex(NULL, p->data, p->len);
422}
423#endif
424
425static char bcm_undeferrstr[BCME_STRLEN];
426
427static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
428
429
430const char *bcmerrorstr(int bcmerror)
431{
432
433
434 ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
435
436 if (bcmerror > 0 || bcmerror < BCME_LAST) {
437 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
438 bcmerror);
439 return bcm_undeferrstr;
440 }
441
442 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
443
444 return bcmerrorstrtable[-bcmerror];
445}
446
447
448const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
449{
450 const bcm_iovar_t *vi;
451 const char *lookup_name;
452
453
454 lookup_name = strrchr(name, ':');
455 if (lookup_name != NULL)
456 lookup_name++;
457 else
458 lookup_name = name;
459
460 ASSERT(table != NULL);
461
462 for (vi = table; vi->name; vi++) {
463 if (!strcmp(vi->name, lookup_name))
464 return vi;
465 }
466
467
468 return NULL;
469}
470
471int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
472{
473 int bcmerror = 0;
474
475
476 switch (vi->type) {
477 case IOVT_BOOL:
478 case IOVT_INT8:
479 case IOVT_INT16:
480 case IOVT_INT32:
481 case IOVT_UINT8:
482 case IOVT_UINT16:
483 case IOVT_UINT32:
484
485 if (len < (int)sizeof(int)) {
486 bcmerror = BCME_BUFTOOSHORT;
487 }
488 break;
489
490 case IOVT_BUFFER:
491
492 if (len < vi->minlen) {
493 bcmerror = BCME_BUFTOOSHORT;
494 }
495 break;
496
497 case IOVT_VOID:
498 if (!set) {
499
500 bcmerror = BCME_UNSUPPORTED;
501 } else if (len) {
502
503 bcmerror = BCME_BUFTOOLONG;
504 }
505 break;
506
507 default:
508
509 ASSERT(0);
510 bcmerror = BCME_UNSUPPORTED;
511 }
512
513 return bcmerror;
514}
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538static const u8 crc8_table[256] = {
539 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
540 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
541 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
542 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
543 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
544 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
545 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
546 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
547 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
548 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
549 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
550 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
551 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
552 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
553 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
554 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
555 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
556 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
557 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
558 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
559 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
560 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
561 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
562 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
563 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
564 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
565 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
566 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
567 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
568 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
569 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
570 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
571};
572
573#define CRC_INNER_LOOP(n, c, x) \
574 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
575
576u8 hndcrc8(u8 *pdata,
577 uint nbytes,
578 u8 crc
579 ) {
580
581
582
583 while (nbytes-- > 0)
584 crc = crc8_table[(crc ^ *pdata++) & 0xff];
585
586 return crc;
587}
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611static const u16 crc16_table[256] = {
612 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
613 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
614 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
615 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
616 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
617 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
618 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
619 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
620 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
621 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
622 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
623 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
624 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
625 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
626 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
627 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
628 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
629 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
630 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
631 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
632 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
633 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
634 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
635 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
636 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
637 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
638 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
639 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
640 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
641 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
642 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
643 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
644};
645
646u16 hndcrc16(u8 *pdata,
647 uint nbytes,
648 u16 crc
649 ) {
650 while (nbytes-- > 0)
651 CRC_INNER_LOOP(16, crc, *pdata++);
652 return crc;
653}
654
655static const u32 crc32_table[256] = {
656 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
657 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
658 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
659 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
660 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
661 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
662 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
663 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
664 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
665 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
666 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
667 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
668 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
669 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
670 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
671 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
672 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
673 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
674 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
675 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
676 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
677 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
678 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
679 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
680 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
681 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
682 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
683 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
684 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
685 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
686 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
687 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
688 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
689 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
690 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
691 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
692 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
693 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
694 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
695 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
696 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
697 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
698 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
699 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
700 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
701 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
702 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
703 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
704 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
705 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
706 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
707 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
708 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
709 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
710 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
711 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
712 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
713 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
714 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
715 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
716 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
717 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
718 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
719 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
720};
721
722u32 hndcrc32(u8 *pdata,
723 uint nbytes,
724 u32 crc
725
726)
727{
728 u8 *pend;
729#ifdef __mips__
730 u8 tmp[4];
731 unsigned long *tptr = (unsigned long *) tmp;
732
733
734 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
735 nbytes -= (pend - pdata);
736 while (pdata < pend)
737 CRC_INNER_LOOP(32, crc, *pdata++);
738
739
740 pend = pdata + (nbytes & 0xfffffffc);
741 while (pdata < pend) {
742 *tptr = *(unsigned long *) pdata;
743 pdata += sizeof(unsigned long *);
744 CRC_INNER_LOOP(32, crc, tmp[0]);
745 CRC_INNER_LOOP(32, crc, tmp[1]);
746 CRC_INNER_LOOP(32, crc, tmp[2]);
747 CRC_INNER_LOOP(32, crc, tmp[3]);
748 }
749
750
751 pend = pdata + (nbytes & 0x03);
752 while (pdata < pend)
753 CRC_INNER_LOOP(32, crc, *pdata++);
754#else
755 pend = pdata + nbytes;
756 while (pdata < pend)
757 CRC_INNER_LOOP(32, crc, *pdata++);
758#endif
759
760 return crc;
761}
762
763
764
765
766
767bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
768{
769 bcm_tlv_t *elt;
770 int totlen;
771
772 elt = (bcm_tlv_t *) buf;
773 totlen = buflen;
774
775
776 while (totlen >= 2) {
777 int len = elt->len;
778
779
780 if ((elt->id == key) && (totlen >= (len + 2)))
781 return elt;
782
783 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
784 totlen -= (len + 2);
785 }
786
787 return NULL;
788}
789
790
791#if defined(BCMDBG)
792int
793bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
794{
795 int i;
796 char *p = buf;
797 char hexstr[16];
798 int slen = 0, nlen = 0;
799 u32 bit;
800 const char *name;
801
802 if (len < 2 || !buf)
803 return 0;
804
805 buf[0] = '\0';
806
807 for (i = 0; flags != 0; i++) {
808 bit = bd[i].bit;
809 name = bd[i].name;
810 if (bit == 0 && flags != 0) {
811
812 snprintf(hexstr, 16, "0x%X", flags);
813 name = hexstr;
814 flags = 0;
815 } else if ((flags & bit) == 0)
816 continue;
817 flags &= ~bit;
818 nlen = strlen(name);
819 slen += nlen;
820
821 if (flags != 0)
822 slen += 1;
823
824 if (len <= slen)
825 break;
826
827 strncpy(p, name, nlen + 1);
828 p += nlen;
829
830 if (flags != 0)
831 p += snprintf(p, 2, " ");
832 len -= slen;
833 }
834
835
836 if (flags != 0) {
837 if (len < 2)
838 p -= 2 - len;
839 p += snprintf(p, 2, ">");
840 }
841
842 return (int)(p - buf);
843}
844
845
846int bcm_format_hex(char *str, const void *bytes, int len)
847{
848 int i;
849 char *p = str;
850 const u8 *src = (const u8 *)bytes;
851
852 for (i = 0; i < len; i++) {
853 p += snprintf(p, 3, "%02X", *src);
854 src++;
855 }
856 return (int)(p - str);
857}
858#endif
859
860
861void prhex(const char *msg, unsigned char *buf, uint nbytes)
862{
863 char line[128], *p;
864 int len = sizeof(line);
865 int nchar;
866 uint i;
867
868 if (msg && (msg[0] != '\0'))
869 printf("%s:\n", msg);
870
871 p = line;
872 for (i = 0; i < nbytes; i++) {
873 if (i % 16 == 0) {
874 nchar = snprintf(p, len, " %04d: ", i);
875 p += nchar;
876 len -= nchar;
877 }
878 if (len > 0) {
879 nchar = snprintf(p, len, "%02x ", buf[i]);
880 p += nchar;
881 len -= nchar;
882 }
883
884 if (i % 16 == 15) {
885 printf("%s\n", line);
886 p = line;
887 len = sizeof(line);
888 }
889 }
890
891
892 if (p != line)
893 printf("%s\n", line);
894}
895
896char *bcm_chipname(uint chipid, char *buf, uint len)
897{
898 const char *fmt;
899
900 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
901 snprintf(buf, len, fmt, chipid);
902 return buf;
903}
904
905uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
906{
907 uint len;
908
909 len = strlen(name) + 1;
910
911 if ((len + datalen) > buflen)
912 return 0;
913
914 strncpy(buf, name, buflen);
915
916
917 memcpy(&buf[len], data, datalen);
918 len += datalen;
919
920 return len;
921}
922
923
924
925
926
927
928
929#define QDBM_OFFSET 153
930#define QDBM_TABLE_LEN 40
931
932
933
934
935#define QDBM_TABLE_LOW_BOUND 6493
936
937
938
939
940
941
942#define QDBM_TABLE_HIGH_BOUND 64938
943
944static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
945
946 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
947 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
948 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
949 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
950 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
951};
952
953u16 bcm_qdbm_to_mw(u8 qdbm)
954{
955 uint factor = 1;
956 int idx = qdbm - QDBM_OFFSET;
957
958 if (idx >= QDBM_TABLE_LEN) {
959
960 return 0xFFFF;
961 }
962
963
964
965
966 while (idx < 0) {
967 idx += 40;
968 factor *= 10;
969 }
970
971
972
973
974 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
975}
976u8 bcm_mw_to_qdbm(u16 mw)
977{
978 u8 qdbm;
979 int offset;
980 uint mw_uint = mw;
981 uint boundary;
982
983
984 if (mw_uint <= 1)
985 return 0;
986
987 offset = QDBM_OFFSET;
988
989
990 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
991 mw_uint *= 10;
992 offset -= 40;
993 }
994
995 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
996 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
997 nqdBm_to_mW_map[qdbm]) / 2;
998 if (mw_uint < boundary)
999 break;
1000 }
1001
1002 qdbm += (u8) offset;
1003
1004 return qdbm;
1005}
1006uint bcm_bitcount(u8 *bitmap, uint length)
1007{
1008 uint bitcount = 0, i;
1009 u8 tmp;
1010 for (i = 0; i < length; i++) {
1011 tmp = bitmap[i];
1012 while (tmp) {
1013 bitcount++;
1014 tmp &= (tmp - 1);
1015 }
1016 }
1017 return bitcount;
1018}
1019
1020void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1021{
1022 b->origsize = b->size = size;
1023 b->origbuf = b->buf = buf;
1024}
1025
1026
1027int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1028{
1029 va_list ap;
1030 int r;
1031
1032 va_start(ap, fmt);
1033 r = vsnprintf(b->buf, b->size, fmt, ap);
1034
1035
1036
1037
1038
1039 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1040 b->size = 0;
1041 } else {
1042 b->size -= r;
1043 b->buf += r;
1044 }
1045
1046 va_end(ap);
1047
1048 return r;
1049}
1050
1051