staging: brcm80211: fix 'do not init statics to 0 or NULL'
[deliverable/linux.git] / drivers / staging / brcm80211 / brcmfmac / linux_osl.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 <linux/version.h>
18
19 #define LINUX_OSL
20 #include <linux/sched.h>
21 #include <typedefs.h>
22 #include <bcmendian.h>
23 #include <linuxver.h>
24 #include <bcmdefs.h>
25 #include <osl.h>
26 #include <bcmutils.h>
27 #include <linux/delay.h>
28 #include <pcicfg.h>
29
30 #define PCI_CFG_RETRY 10
31
32 #define OS_HANDLE_MAGIC 0x1234abcd
33 #define BCM_MEM_FILENAME_LEN 24
34
35 #ifdef DHD_USE_STATIC_BUF
36 #define MAX_STATIC_BUF_NUM 16
37 #define STATIC_BUF_SIZE (PAGE_SIZE*2)
38 #define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE)
39 typedef struct bcm_static_buf {
40 struct semaphore static_sem;
41 unsigned char *buf_ptr;
42 unsigned char buf_use[MAX_STATIC_BUF_NUM];
43 } bcm_static_buf_t;
44
45 static bcm_static_buf_t *bcm_static_buf;
46
47 #define MAX_STATIC_PKT_NUM 8
48 typedef struct bcm_static_pkt {
49 struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM];
50 struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM];
51 struct semaphore osl_pkt_sem;
52 unsigned char pkt_use[MAX_STATIC_PKT_NUM * 2];
53 } bcm_static_pkt_t;
54 static bcm_static_pkt_t *bcm_static_skb;
55 #endif /* DHD_USE_STATIC_BUF */
56
57 typedef struct bcm_mem_link {
58 struct bcm_mem_link *prev;
59 struct bcm_mem_link *next;
60 uint size;
61 int line;
62 char file[BCM_MEM_FILENAME_LEN];
63 } bcm_mem_link_t;
64
65 struct osl_info {
66 osl_pubinfo_t pub;
67 uint magic;
68 void *pdev;
69 uint malloced;
70 uint failed;
71 uint bustype;
72 bcm_mem_link_t *dbgmem_list;
73 };
74
75 static int16 linuxbcmerrormap[] = { 0,
76 -EINVAL,
77 -EINVAL,
78 -EINVAL,
79 -EINVAL,
80 -EINVAL,
81 -EINVAL,
82 -EINVAL,
83 -EINVAL,
84 -EINVAL,
85 -EINVAL,
86 -EINVAL,
87 -EINVAL,
88 -EINVAL,
89 -E2BIG,
90 -E2BIG,
91 -EBUSY,
92 -EINVAL,
93 -EINVAL,
94 -EINVAL,
95 -EINVAL,
96 -EFAULT,
97 -ENOMEM,
98 -EOPNOTSUPP,
99 -EMSGSIZE,
100 -EINVAL,
101 -EPERM,
102 -ENOMEM,
103 -EINVAL,
104 -ERANGE,
105 -EINVAL,
106 -EINVAL,
107 -EINVAL,
108 -EINVAL,
109 -EINVAL,
110 -EIO,
111 -ENODEV,
112 -EINVAL,
113 -EIO,
114 -EIO,
115 -EINVAL,
116 -EINVAL,
117 -ENODATA,
118
119 #if BCME_LAST != BCME_NONRESIDENT
120 #error "You need to add a OS error translation in the linuxbcmerrormap \
121 for new error code defined in bcmutils.h"
122 #endif
123 };
124
125 /* Global ASSERT type flag */
126 uint32 g_assert_type;
127
128 int osl_error(int bcmerror)
129 {
130 if (bcmerror > 0)
131 bcmerror = 0;
132 else if (bcmerror < BCME_LAST)
133 bcmerror = BCME_ERROR;
134
135 return linuxbcmerrormap[-bcmerror];
136 }
137
138 void *dhd_os_prealloc(int section, unsigned long size);
139 osl_t *osl_attach(void *pdev, uint bustype, bool pkttag)
140 {
141 osl_t *osh;
142
143 osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
144 ASSERT(osh);
145
146 bzero(osh, sizeof(osl_t));
147
148 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
149
150 osh->magic = OS_HANDLE_MAGIC;
151 osh->malloced = 0;
152 osh->failed = 0;
153 osh->dbgmem_list = NULL;
154 osh->pdev = pdev;
155 osh->pub.pkttag = pkttag;
156 osh->bustype = bustype;
157
158 switch (bustype) {
159 case PCI_BUS:
160 case SI_BUS:
161 case PCMCIA_BUS:
162 osh->pub.mmbus = TRUE;
163 break;
164 case JTAG_BUS:
165 case SDIO_BUS:
166 case USB_BUS:
167 case SPI_BUS:
168 osh->pub.mmbus = FALSE;
169 break;
170 default:
171 ASSERT(FALSE);
172 break;
173 }
174
175 #ifdef DHD_USE_STATIC_BUF
176
177 if (!bcm_static_buf) {
178 bcm_static_buf = (bcm_static_buf_t *) dhd_os_prealloc(3,
179 STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN);
180 if (!bcm_static_buf) {
181 printk(KERN_ERR "can not alloc static buf!\n");
182 } else
183 printk(KERN_ERR "alloc static buf at %x!\n",
184 (unsigned int)bcm_static_buf);
185
186 init_MUTEX(&bcm_static_buf->static_sem);
187
188 bcm_static_buf->buf_ptr =
189 (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
190
191 }
192
193 if (!bcm_static_skb) {
194 int i;
195 void *skb_buff_ptr = 0;
196 bcm_static_skb =
197 (bcm_static_pkt_t *) ((char *)bcm_static_buf + 2048);
198 skb_buff_ptr = dhd_os_prealloc(4, 0);
199
200 bcopy(skb_buff_ptr, bcm_static_skb,
201 sizeof(struct sk_buff *) * 16);
202 for (i = 0; i < MAX_STATIC_PKT_NUM * 2; i++)
203 bcm_static_skb->pkt_use[i] = 0;
204
205 init_MUTEX(&bcm_static_skb->osl_pkt_sem);
206 }
207 #endif /* DHD_USE_STATIC_BUF */
208 return osh;
209 }
210
211 void osl_detach(osl_t *osh)
212 {
213 if (osh == NULL)
214 return;
215
216 #ifdef DHD_USE_STATIC_BUF
217 if (bcm_static_buf)
218 bcm_static_buf = 0;
219
220 if (bcm_static_skb)
221 bcm_static_skb = 0;
222 #endif
223 ASSERT(osh->magic == OS_HANDLE_MAGIC);
224 kfree(osh);
225 }
226
227 void *osl_pktget(osl_t *osh, uint len)
228 {
229 struct sk_buff *skb;
230
231 skb = dev_alloc_skb(len);
232 if (skb) {
233 skb_put(skb, len);
234 skb->priority = 0;
235
236 osh->pub.pktalloced++;
237 }
238
239 return (void *)skb;
240 }
241
242 void osl_pktfree(osl_t *osh, void *p, bool send)
243 {
244 struct sk_buff *skb, *nskb;
245
246 skb = (struct sk_buff *)p;
247
248 if (send && osh->pub.tx_fn)
249 osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
250
251 while (skb) {
252 nskb = skb->next;
253 skb->next = NULL;
254
255 if (skb->destructor)
256 dev_kfree_skb_any(skb);
257 else
258 dev_kfree_skb(skb);
259
260 osh->pub.pktalloced--;
261
262 skb = nskb;
263 }
264 }
265
266 #ifdef DHD_USE_STATIC_BUF
267 void *osl_pktget_static(osl_t *osh, uint len)
268 {
269 int i = 0;
270 struct sk_buff *skb;
271
272 if (len > (PAGE_SIZE * 2)) {
273 printk(KERN_ERR "Do we really need this big skb??\n");
274 return osl_pktget(osh, len);
275 }
276
277 down(&bcm_static_skb->osl_pkt_sem);
278 if (len <= PAGE_SIZE) {
279 for (i = 0; i < MAX_STATIC_PKT_NUM; i++) {
280 if (bcm_static_skb->pkt_use[i] == 0)
281 break;
282 }
283
284 if (i != MAX_STATIC_PKT_NUM) {
285 bcm_static_skb->pkt_use[i] = 1;
286 up(&bcm_static_skb->osl_pkt_sem);
287
288 skb = bcm_static_skb->skb_4k[i];
289 skb->tail = skb->data + len;
290 skb->len = len;
291
292 return skb;
293 }
294 }
295
296 for (i = 0; i < MAX_STATIC_PKT_NUM; i++) {
297 if (bcm_static_skb->pkt_use[i + MAX_STATIC_PKT_NUM] == 0)
298 break;
299 }
300
301 if (i != MAX_STATIC_PKT_NUM) {
302 bcm_static_skb->pkt_use[i + MAX_STATIC_PKT_NUM] = 1;
303 up(&bcm_static_skb->osl_pkt_sem);
304 skb = bcm_static_skb->skb_8k[i];
305 skb->tail = skb->data + len;
306 skb->len = len;
307
308 return skb;
309 }
310
311 up(&bcm_static_skb->osl_pkt_sem);
312 printk(KERN_ERR "all static pkt in use!\n");
313 return osl_pktget(osh, len);
314 }
315
316 void osl_pktfree_static(osl_t *osh, void *p, bool send)
317 {
318 int i;
319
320 for (i = 0; i < MAX_STATIC_PKT_NUM * 2; i++) {
321 if (p == bcm_static_skb->skb_4k[i]) {
322 down(&bcm_static_skb->osl_pkt_sem);
323 bcm_static_skb->pkt_use[i] = 0;
324 up(&bcm_static_skb->osl_pkt_sem);
325
326 return;
327 }
328 }
329 return osl_pktfree(osh, p, send);
330 }
331 #endif /* DHD_USE_STATIC_BUF */
332
333 uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size)
334 {
335 uint val = 0;
336 uint retry = PCI_CFG_RETRY;
337
338 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
339 ASSERT(size == 4);
340
341 do {
342 pci_read_config_dword(osh->pdev, offset, &val);
343 if (val != 0xffffffff)
344 break;
345 } while (retry--);
346
347 return val;
348 }
349
350 void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
351 {
352 uint retry = PCI_CFG_RETRY;
353
354 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
355 ASSERT(size == 4);
356
357 do {
358 pci_write_config_dword(osh->pdev, offset, val);
359 if (offset != PCI_BAR0_WIN)
360 break;
361 if (osl_pci_read_config(osh, offset, size) == val)
362 break;
363 } while (retry--);
364
365 }
366
367 uint osl_pci_bus(osl_t *osh)
368 {
369 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
370
371 return ((struct pci_dev *)osh->pdev)->bus->number;
372 }
373
374 uint osl_pci_slot(osl_t *osh)
375 {
376 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
377
378 return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
379 }
380
381 static void
382 osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
383 {
384 }
385
386 void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size)
387 {
388 osl_pcmcia_attr(osh, offset, (char *)buf, size, FALSE);
389 }
390
391 void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size)
392 {
393 osl_pcmcia_attr(osh, offset, (char *)buf, size, TRUE);
394 }
395
396 void *osl_malloc(osl_t *osh, uint size)
397 {
398 void *addr;
399
400 if (osh)
401 ASSERT(osh->magic == OS_HANDLE_MAGIC);
402
403 #ifdef DHD_USE_STATIC_BUF
404 if (bcm_static_buf) {
405 int i = 0;
406 if ((size >= PAGE_SIZE) && (size <= STATIC_BUF_SIZE)) {
407 down(&bcm_static_buf->static_sem);
408 for (i = 0; i < MAX_STATIC_BUF_NUM; i++) {
409 if (bcm_static_buf->buf_use[i] == 0)
410 break;
411 }
412 if (i == MAX_STATIC_BUF_NUM) {
413 up(&bcm_static_buf->static_sem);
414 printk(KERN_ERR "all static buff in use!\n");
415 goto original;
416 }
417 bcm_static_buf->buf_use[i] = 1;
418 up(&bcm_static_buf->static_sem);
419
420 bzero(bcm_static_buf->buf_ptr + STATIC_BUF_SIZE * i,
421 size);
422 if (osh)
423 osh->malloced += size;
424
425 return (void *)(bcm_static_buf->buf_ptr +
426 STATIC_BUF_SIZE * i);
427 }
428 }
429 original:
430 #endif /* DHD_USE_STATIC_BUF */
431
432 addr = kmalloc(size, GFP_ATOMIC);
433 if (addr == NULL) {
434 if (osh)
435 osh->failed++;
436 return NULL;
437 }
438 if (osh)
439 osh->malloced += size;
440
441 return addr;
442 }
443
444 void osl_mfree(osl_t *osh, void *addr, uint size)
445 {
446 #ifdef DHD_USE_STATIC_BUF
447 if (bcm_static_buf) {
448 if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr
449 <= ((unsigned char *)
450 bcm_static_buf +
451 STATIC_BUF_TOTAL_LEN))) {
452 int buf_idx = 0;
453 buf_idx =
454 ((unsigned char *)addr -
455 bcm_static_buf->buf_ptr) / STATIC_BUF_SIZE;
456 down(&bcm_static_buf->static_sem);
457 bcm_static_buf->buf_use[buf_idx] = 0;
458 up(&bcm_static_buf->static_sem);
459
460 if (osh) {
461 ASSERT(osh->magic == OS_HANDLE_MAGIC);
462 osh->malloced -= size;
463 }
464 return;
465 }
466 }
467 #endif /* DHD_USE_STATIC_BUF */
468 if (osh) {
469 ASSERT(osh->magic == OS_HANDLE_MAGIC);
470 osh->malloced -= size;
471 }
472 kfree(addr);
473 }
474
475 uint osl_malloced(osl_t *osh)
476 {
477 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
478 return osh->malloced;
479 }
480
481 uint osl_malloc_failed(osl_t *osh)
482 {
483 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
484 return osh->failed;
485 }
486
487 void *osl_dma_alloc_consistent(osl_t *osh, uint size, unsigned long *pap)
488 {
489 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
490
491 return pci_alloc_consistent(osh->pdev, size, (dma_addr_t *) pap);
492 }
493
494 void osl_dma_free_consistent(osl_t *osh, void *va, uint size, unsigned long pa)
495 {
496 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
497
498 pci_free_consistent(osh->pdev, size, va, (dma_addr_t) pa);
499 }
500
501 uint osl_dma_map(osl_t *osh, void *va, uint size, int direction)
502 {
503 int dir;
504
505 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
506 dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
507 return pci_map_single(osh->pdev, va, size, dir);
508 }
509
510 void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
511 {
512 int dir;
513
514 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
515 dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
516 pci_unmap_single(osh->pdev, (uint32) pa, size, dir);
517 }
518
519 #if defined(BCMDBG_ASSERT)
520 void osl_assert(char *exp, char *file, int line)
521 {
522 char tempbuf[256];
523 char *basename;
524
525 basename = strrchr(file, '/');
526 /* skip the '/' */
527 if (basename)
528 basename++;
529
530 if (!basename)
531 basename = file;
532
533 #ifdef BCMDBG_ASSERT
534 snprintf(tempbuf, 256,
535 "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
536 basename, line);
537
538 /* Print assert message and give it time to be written
539 to /var/log/messages */
540 if (!in_interrupt()) {
541 const int delay = 3;
542 printk(KERN_ERR "%s", tempbuf);
543 printk(KERN_ERR "panic in %d seconds\n", delay);
544 set_current_state(TASK_INTERRUPTIBLE);
545 schedule_timeout(delay * HZ);
546 }
547
548 switch (g_assert_type) {
549 case 0:
550 panic(KERN_ERR "%s", tempbuf);
551 break;
552 case 1:
553 printk(KERN_ERR "%s", tempbuf);
554 BUG();
555 break;
556 case 2:
557 printk(KERN_ERR "%s", tempbuf);
558 break;
559 default:
560 break;
561 }
562 #endif /* BCMDBG_ASSERT */
563
564 }
565 #endif /* defined(BCMDBG_ASSERT) */
566
567 void osl_delay(uint usec)
568 {
569 uint d;
570
571 while (usec > 0) {
572 d = MIN(usec, 1000);
573 udelay(d);
574 usec -= d;
575 }
576 }
577
578 void *osl_pktdup(osl_t *osh, void *skb)
579 {
580 void *p;
581
582 p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC);
583 if (p == NULL)
584 return NULL;
585
586 if (osh->pub.pkttag)
587 bzero((void *)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
588
589 osh->pub.pktalloced++;
590 return p;
591 }
This page took 0.044839 seconds and 5 git commands to generate.