staging: brcm80211: Coalesce osl_dma_alloc_consistent between fullmac and softmac
[linux-2.6/kvm.git] / drivers / staging / brcm80211 / util / linux_osl.c
blob391f33caafdef5167742155d58afc95864318ae7
1 /*
2 * Copyright (c) 2010 Broadcom Corporation
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.
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.
17 #include <typedefs.h>
18 #include <bcmendian.h>
19 #include <linuxver.h>
20 #include <bcmdefs.h>
21 #include <osl.h>
22 #include <bcmutils.h>
23 #include <linux/delay.h>
24 #ifdef mips
25 #include <asm/paccess.h>
26 #endif /* mips */
27 #include <pcicfg.h>
29 #include <linux/fs.h>
31 #define PCI_CFG_RETRY 10
33 #define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */
34 #define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */
36 #if defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF)
37 #define MAX_STATIC_BUF_NUM 16
38 #define STATIC_BUF_SIZE (PAGE_SIZE*2)
39 #define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE)
40 typedef struct bcm_static_buf {
41 struct semaphore static_sem;
42 unsigned char *buf_ptr;
43 unsigned char buf_use[MAX_STATIC_BUF_NUM];
44 } bcm_static_buf_t;
46 static bcm_static_buf_t *bcm_static_buf = 0;
48 #define MAX_STATIC_PKT_NUM 8
49 typedef struct bcm_static_pkt {
50 struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM];
51 struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM];
52 struct semaphore osl_pkt_sem;
53 unsigned char pkt_use[MAX_STATIC_PKT_NUM * 2];
54 } bcm_static_pkt_t;
55 static bcm_static_pkt_t *bcm_static_skb = 0;
56 #endif /* DHD_USE_STATIC_BUF */
58 struct osl_info {
59 osl_pubinfo_t pub;
60 uint magic;
61 void *pdev;
62 uint malloced;
63 uint failed;
64 uint bustype;
67 /* Global ASSERT type flag */
68 u32 g_assert_type;
70 #ifdef BRCM_FULLMAC
71 static s16 linuxbcmerrormap[] = { 0, /* 0 */
72 -EINVAL, /* BCME_ERROR */
73 -EINVAL, /* BCME_BADARG */
74 -EINVAL, /* BCME_BADOPTION */
75 -EINVAL, /* BCME_NOTUP */
76 -EINVAL, /* BCME_NOTDOWN */
77 -EINVAL, /* BCME_NOTAP */
78 -EINVAL, /* BCME_NOTSTA */
79 -EINVAL, /* BCME_BADKEYIDX */
80 -EINVAL, /* BCME_RADIOOFF */
81 -EINVAL, /* BCME_NOTBANDLOCKED */
82 -EINVAL, /* BCME_NOCLK */
83 -EINVAL, /* BCME_BADRATESET */
84 -EINVAL, /* BCME_BADBAND */
85 -E2BIG, /* BCME_BUFTOOSHORT */
86 -E2BIG, /* BCME_BUFTOOLONG */
87 -EBUSY, /* BCME_BUSY */
88 -EINVAL, /* BCME_NOTASSOCIATED */
89 -EINVAL, /* BCME_BADSSIDLEN */
90 -EINVAL, /* BCME_OUTOFRANGECHAN */
91 -EINVAL, /* BCME_BADCHAN */
92 -EFAULT, /* BCME_BADADDR */
93 -ENOMEM, /* BCME_NORESOURCE */
94 -EOPNOTSUPP, /* BCME_UNSUPPORTED */
95 -EMSGSIZE, /* BCME_BADLENGTH */
96 -EINVAL, /* BCME_NOTREADY */
97 -EPERM, /* BCME_NOTPERMITTED */
98 -ENOMEM, /* BCME_NOMEM */
99 -EINVAL, /* BCME_ASSOCIATED */
100 -ERANGE, /* BCME_RANGE */
101 -EINVAL, /* BCME_NOTFOUND */
102 -EINVAL, /* BCME_WME_NOT_ENABLED */
103 -EINVAL, /* BCME_TSPEC_NOTFOUND */
104 -EINVAL, /* BCME_ACM_NOTSUPPORTED */
105 -EINVAL, /* BCME_NOT_WME_ASSOCIATION */
106 -EIO, /* BCME_SDIO_ERROR */
107 -ENODEV, /* BCME_DONGLE_DOWN */
108 -EINVAL, /* BCME_VERSION */
109 -EIO, /* BCME_TXFAIL */
110 -EIO, /* BCME_RXFAIL */
111 -EINVAL, /* BCME_NODEVICE */
112 -EINVAL, /* BCME_NMODE_DISABLED */
113 -ENODATA, /* BCME_NONRESIDENT */
115 /* When an new error code is added to bcmutils.h, add os
116 * spcecific error translation here as well
118 /* check if BCME_LAST changed since the last time this function was updated */
119 #if BCME_LAST != -42
120 #error "You need to add a OS error translation in the linuxbcmerrormap \
121 for new error code defined in bcmutils.h"
122 #endif
125 /* translate bcmerrors into linux errors */
126 int osl_error(int bcmerror)
128 if (bcmerror > 0)
129 bcmerror = 0;
130 else if (bcmerror < BCME_LAST)
131 bcmerror = BCME_ERROR;
133 /* Array bounds covered by ASSERT in osl_attach */
134 return linuxbcmerrormap[-bcmerror];
136 #endif /* BRCM_FULLMAC */
138 osl_t *osl_attach(void *pdev, uint bustype, bool pkttag)
140 osl_t *osh;
142 osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
143 ASSERT(osh);
145 bzero(osh, sizeof(osl_t));
147 #ifdef BRCM_FULLMAC
148 /* Check that error map has the right number of entries in it */
149 ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(linuxbcmerrormap) - 1));
150 #endif /* BRCM_FULLMAC */
152 osh->magic = OS_HANDLE_MAGIC;
153 osh->malloced = 0;
154 osh->failed = 0;
155 osh->pdev = pdev;
156 osh->pub.pkttag = pkttag;
157 osh->bustype = bustype;
159 switch (bustype) {
160 case PCI_BUS:
161 case SI_BUS:
162 case PCMCIA_BUS:
163 osh->pub.mmbus = TRUE;
164 break;
165 case JTAG_BUS:
166 case SDIO_BUS:
167 case USB_BUS:
168 case SPI_BUS:
169 case RPC_BUS:
170 osh->pub.mmbus = FALSE;
171 break;
172 default:
173 ASSERT(FALSE);
174 break;
177 #if defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF)
178 if (!bcm_static_buf) {
179 if (!(bcm_static_buf =
180 (bcm_static_buf_t *) dhd_os_prealloc(3,
181 STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) {
182 printk(KERN_ERR "can not alloc static buf!\n");
183 } else
184 printk(KERN_ERR "alloc static buf at %x!\n",
185 (unsigned int)bcm_static_buf);
187 init_MUTEX(&bcm_static_buf->static_sem);
189 bcm_static_buf->buf_ptr =
190 (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
194 if (!bcm_static_skb) {
195 int i;
196 void *skb_buff_ptr = 0;
197 bcm_static_skb =
198 (bcm_static_pkt_t *) ((char *)bcm_static_buf + 2048);
199 skb_buff_ptr = dhd_os_prealloc(4, 0);
201 bcopy(skb_buff_ptr, bcm_static_skb,
202 sizeof(struct sk_buff *) * 16);
203 for (i = 0; i < MAX_STATIC_PKT_NUM * 2; i++)
204 bcm_static_skb->pkt_use[i] = 0;
206 init_MUTEX(&bcm_static_skb->osl_pkt_sem);
208 #endif /* defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF) */
210 #if defined(BCMDBG) && !defined(BRCM_FULLMAC)
211 if (pkttag) {
212 struct sk_buff *skb;
213 ASSERT(OSL_PKTTAG_SZ <= sizeof(skb->cb));
215 #endif
216 return osh;
219 void osl_detach(osl_t *osh)
221 if (osh == NULL)
222 return;
224 #if defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF)
225 if (bcm_static_buf)
226 bcm_static_buf = 0;
228 if (bcm_static_skb)
229 bcm_static_skb = 0;
230 #endif
231 ASSERT(osh->magic == OS_HANDLE_MAGIC);
232 kfree(osh);
235 /* Return a new packet. zero out pkttag */
236 void *BCMFASTPATH osl_pktget(osl_t *osh, uint len)
238 struct sk_buff *skb;
240 skb = dev_alloc_skb(len);
241 if (skb) {
242 skb_put(skb, len);
243 skb->priority = 0;
245 osh->pub.pktalloced++;
248 return (void *)skb;
251 /* Free the driver packet. Free the tag if present */
252 void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send)
254 struct sk_buff *skb, *nskb;
255 int nest = 0;
257 skb = (struct sk_buff *)p;
258 ASSERT(skb);
260 if (send && osh->pub.tx_fn)
261 osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
263 /* perversion: we use skb->next to chain multi-skb packets */
264 while (skb) {
265 nskb = skb->next;
266 skb->next = NULL;
268 if (skb->destructor)
269 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
270 * destructor exists
272 dev_kfree_skb_any(skb);
273 else
274 /* can free immediately (even in_irq()) if destructor
275 * does not exist
277 dev_kfree_skb(skb);
279 osh->pub.pktalloced--;
280 nest++;
281 skb = nskb;
285 #if defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF)
286 void *osl_pktget_static(osl_t *osh, uint len)
288 int i = 0;
289 struct sk_buff *skb;
291 if (len > (PAGE_SIZE * 2)) {
292 printk(KERN_ERR "Do we really need this big skb??\n");
293 return osl_pktget(osh, len);
296 down(&bcm_static_skb->osl_pkt_sem);
297 if (len <= PAGE_SIZE) {
298 for (i = 0; i < MAX_STATIC_PKT_NUM; i++) {
299 if (bcm_static_skb->pkt_use[i] == 0)
300 break;
303 if (i != MAX_STATIC_PKT_NUM) {
304 bcm_static_skb->pkt_use[i] = 1;
305 up(&bcm_static_skb->osl_pkt_sem);
307 skb = bcm_static_skb->skb_4k[i];
308 skb->tail = skb->data + len;
309 skb->len = len;
311 return skb;
315 for (i = 0; i < MAX_STATIC_PKT_NUM; i++) {
316 if (bcm_static_skb->pkt_use[i + MAX_STATIC_PKT_NUM] == 0)
317 break;
320 if (i != MAX_STATIC_PKT_NUM) {
321 bcm_static_skb->pkt_use[i + MAX_STATIC_PKT_NUM] = 1;
322 up(&bcm_static_skb->osl_pkt_sem);
323 skb = bcm_static_skb->skb_8k[i];
324 skb->tail = skb->data + len;
325 skb->len = len;
327 return skb;
330 up(&bcm_static_skb->osl_pkt_sem);
331 printk(KERN_ERR "all static pkt in use!\n");
332 return osl_pktget(osh, len);
335 void osl_pktfree_static(osl_t *osh, void *p, bool send)
337 int i;
339 for (i = 0; i < MAX_STATIC_PKT_NUM * 2; i++) {
340 if (p == bcm_static_skb->skb_4k[i]) {
341 down(&bcm_static_skb->osl_pkt_sem);
342 bcm_static_skb->pkt_use[i] = 0;
343 up(&bcm_static_skb->osl_pkt_sem);
345 return;
348 return osl_pktfree(osh, p, send);
350 #endif /* defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF) */
352 u32 osl_pci_read_config(osl_t *osh, uint offset, uint size)
354 uint val = 0;
355 uint retry = PCI_CFG_RETRY;
357 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
359 /* only 4byte access supported */
360 ASSERT(size == 4);
362 do {
363 pci_read_config_dword(osh->pdev, offset, &val);
364 if (val != 0xffffffff)
365 break;
366 } while (retry--);
368 #ifdef BCMDBG
369 if (retry < PCI_CFG_RETRY)
370 printk("PCI CONFIG READ access to %d required %d retries\n",
371 offset, (PCI_CFG_RETRY - retry));
372 #endif /* BCMDBG */
374 return val;
377 void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
379 uint retry = PCI_CFG_RETRY;
381 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
383 /* only 4byte access supported */
384 ASSERT(size == 4);
386 do {
387 pci_write_config_dword(osh->pdev, offset, val);
388 if (offset != PCI_BAR0_WIN)
389 break;
390 if (osl_pci_read_config(osh, offset, size) == val)
391 break;
392 } while (retry--);
394 #if defined(BCMDBG) && !defined(BRCM_FULLMAC)
395 if (retry < PCI_CFG_RETRY)
396 printk("PCI CONFIG WRITE access to %d required %d retries\n",
397 offset, (PCI_CFG_RETRY - retry));
398 #endif /* BCMDBG */
401 /* return bus # for the pci device pointed by osh->pdev */
402 uint osl_pci_bus(osl_t *osh)
404 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
406 return ((struct pci_dev *)osh->pdev)->bus->number;
409 /* return slot # for the pci device pointed by osh->pdev */
410 uint osl_pci_slot(osl_t *osh)
412 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
414 return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
417 void *osl_malloc(osl_t *osh, uint size)
419 void *addr;
421 /* only ASSERT if osh is defined */
422 if (osh)
423 ASSERT(osh->magic == OS_HANDLE_MAGIC);
425 #if defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF)
426 if (bcm_static_buf) {
427 int i = 0;
428 if ((size >= PAGE_SIZE) && (size <= STATIC_BUF_SIZE)) {
429 down(&bcm_static_buf->static_sem);
430 for (i = 0; i < MAX_STATIC_BUF_NUM; i++) {
431 if (bcm_static_buf->buf_use[i] == 0)
432 break;
434 if (i == MAX_STATIC_BUF_NUM) {
435 up(&bcm_static_buf->static_sem);
436 printk(KERN_ERR "all static buff in use!\n");
437 goto original;
439 bcm_static_buf->buf_use[i] = 1;
440 up(&bcm_static_buf->static_sem);
442 bzero(bcm_static_buf->buf_ptr + STATIC_BUF_SIZE * i,
443 size);
444 if (osh)
445 osh->malloced += size;
447 return (void *)(bcm_static_buf->buf_ptr +
448 STATIC_BUF_SIZE * i);
451 original:
452 #endif /* defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF) */
454 addr = kmalloc(size, GFP_ATOMIC);
455 if (addr == NULL) {
456 if (osh)
457 osh->failed++;
458 return NULL;
460 if (osh)
461 osh->malloced += size;
463 return addr;
466 void osl_mfree(osl_t *osh, void *addr, uint size)
468 #if defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF)
469 if (bcm_static_buf) {
470 if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr
471 <= ((unsigned char *)
472 bcm_static_buf +
473 STATIC_BUF_TOTAL_LEN))) {
474 int buf_idx = 0;
475 buf_idx =
476 ((unsigned char *)addr -
477 bcm_static_buf->buf_ptr) / STATIC_BUF_SIZE;
478 down(&bcm_static_buf->static_sem);
479 bcm_static_buf->buf_use[buf_idx] = 0;
480 up(&bcm_static_buf->static_sem);
482 if (osh) {
483 ASSERT(osh->magic == OS_HANDLE_MAGIC);
484 osh->malloced -= size;
486 return;
489 #endif /* defined(BRCM_FULLMAC) && defined(DHD_USE_STATIC_BUF) */
490 if (osh) {
491 ASSERT(osh->magic == OS_HANDLE_MAGIC);
492 osh->malloced -= size;
494 kfree(addr);
497 uint osl_malloced(osl_t *osh)
499 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
500 return osh->malloced;
503 uint osl_dma_consistent_align(void)
505 return PAGE_SIZE;
508 void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align_bits,
509 uint *alloced, unsigned long *pap)
511 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
513 if (align_bits) {
514 u16 align = (1 << align_bits);
515 if (!IS_ALIGNED(DMA_CONSISTENT_ALIGN, align))
516 size += align;
517 *alloced = size;
519 return pci_alloc_consistent(osh->pdev, size, (dma_addr_t *) pap);
522 void osl_dma_free_consistent(osl_t *osh, void *va, uint size, unsigned long pa)
524 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
526 pci_free_consistent(osh->pdev, size, va, (dma_addr_t) pa);
529 uint BCMFASTPATH osl_dma_map(osl_t *osh, void *va, uint size, int direction)
531 int dir;
533 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
534 dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
535 return pci_map_single(osh->pdev, va, size, dir);
538 void BCMFASTPATH osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
540 int dir;
542 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
543 dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
544 pci_unmap_single(osh->pdev, (u32) pa, size, dir);
547 #if defined(BCMDBG_ASSERT)
548 void osl_assert(char *exp, char *file, int line)
550 char tempbuf[256];
551 char *basename;
553 basename = strrchr(file, '/');
554 /* skip the '/' */
555 if (basename)
556 basename++;
558 if (!basename)
559 basename = file;
561 #ifdef BCMDBG_ASSERT
562 snprintf(tempbuf, 256,
563 "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
564 basename, line);
566 /* Print assert message and give it time to be written to /var/log/messages */
567 if (!in_interrupt()) {
568 const int delay = 3;
569 printk(KERN_ERR "%s", tempbuf);
570 printk(KERN_ERR "panic in %d seconds\n", delay);
571 set_current_state(TASK_INTERRUPTIBLE);
572 schedule_timeout(delay * HZ);
575 switch (g_assert_type) {
576 case 0:
577 panic(KERN_ERR "%s", tempbuf);
578 break;
579 case 1:
580 printk(KERN_ERR "%s", tempbuf);
581 BUG();
582 break;
583 case 2:
584 printk(KERN_ERR "%s", tempbuf);
585 break;
586 default:
587 break;
589 #endif /* BCMDBG_ASSERT */
592 #endif /* defined(BCMDBG_ASSERT) */
594 void osl_delay(uint usec)
596 uint d;
598 while (usec > 0) {
599 d = min(usec, (uint)1000);
600 udelay(d);
601 usec -= d;
605 #if defined(BCMSDIO) && !defined(BRCM_FULLMAC)
606 u8 osl_readb(osl_t *osh, volatile u8 *r)
608 osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn;
609 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
611 return (u8) ((rreg) (ctx, (void *)r, sizeof(u8)));
614 u16 osl_readw(osl_t *osh, volatile u16 *r)
616 osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn;
617 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
619 return (u16) ((rreg) (ctx, (void *)r, sizeof(u16)));
622 u32 osl_readl(osl_t *osh, volatile u32 *r)
624 osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn;
625 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
627 return (u32) ((rreg) (ctx, (void *)r, sizeof(u32)));
630 void osl_writeb(osl_t *osh, volatile u8 *r, u8 v)
632 osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn;
633 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
635 ((wreg) (ctx, (void *)r, v, sizeof(u8)));
638 void osl_writew(osl_t *osh, volatile u16 *r, u16 v)
640 osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn;
641 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
643 ((wreg) (ctx, (void *)r, v, sizeof(u16)));
646 void osl_writel(osl_t *osh, volatile u32 *r, u32 v)
648 osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn;
649 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
651 ((wreg) (ctx, (void *)r, v, sizeof(u32)));
653 #endif /* BCMSDIO */