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