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