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.
18 #include <bcmendian.h>
23 #include <linux/delay.h>
25 #include <asm/paccess.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 #ifdef 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
];
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];
55 static bcm_static_pkt_t
*bcm_static_skb
= 0;
56 #endif /* DHD_USE_STATIC_BUF */
57 typedef struct bcm_mem_link
{
58 struct bcm_mem_link
*prev
;
59 struct bcm_mem_link
*next
;
62 char file
[BCM_MEM_FILENAME_LEN
];
72 bcm_mem_link_t
*dbgmem_list
;
75 /* Global ASSERT type flag */
78 static int16 linuxbcmerrormap
[] = { 0, /* 0 */
79 -EINVAL
, /* BCME_ERROR */
80 -EINVAL
, /* BCME_BADARG */
81 -EINVAL
, /* BCME_BADOPTION */
82 -EINVAL
, /* BCME_NOTUP */
83 -EINVAL
, /* BCME_NOTDOWN */
84 -EINVAL
, /* BCME_NOTAP */
85 -EINVAL
, /* BCME_NOTSTA */
86 -EINVAL
, /* BCME_BADKEYIDX */
87 -EINVAL
, /* BCME_RADIOOFF */
88 -EINVAL
, /* BCME_NOTBANDLOCKED */
89 -EINVAL
, /* BCME_NOCLK */
90 -EINVAL
, /* BCME_BADRATESET */
91 -EINVAL
, /* BCME_BADBAND */
92 -E2BIG
, /* BCME_BUFTOOSHORT */
93 -E2BIG
, /* BCME_BUFTOOLONG */
94 -EBUSY
, /* BCME_BUSY */
95 -EINVAL
, /* BCME_NOTASSOCIATED */
96 -EINVAL
, /* BCME_BADSSIDLEN */
97 -EINVAL
, /* BCME_OUTOFRANGECHAN */
98 -EINVAL
, /* BCME_BADCHAN */
99 -EFAULT
, /* BCME_BADADDR */
100 -ENOMEM
, /* BCME_NORESOURCE */
101 -EOPNOTSUPP
, /* BCME_UNSUPPORTED */
102 -EMSGSIZE
, /* BCME_BADLENGTH */
103 -EINVAL
, /* BCME_NOTREADY */
104 -EPERM
, /* BCME_NOTPERMITTED */
105 -ENOMEM
, /* BCME_NOMEM */
106 -EINVAL
, /* BCME_ASSOCIATED */
107 -ERANGE
, /* BCME_RANGE */
108 -EINVAL
, /* BCME_NOTFOUND */
109 -EINVAL
, /* BCME_WME_NOT_ENABLED */
110 -EINVAL
, /* BCME_TSPEC_NOTFOUND */
111 -EINVAL
, /* BCME_ACM_NOTSUPPORTED */
112 -EINVAL
, /* BCME_NOT_WME_ASSOCIATION */
113 -EIO
, /* BCME_SDIO_ERROR */
114 -ENODEV
, /* BCME_DONGLE_DOWN */
115 -EINVAL
, /* BCME_VERSION */
116 -EIO
, /* BCME_TXFAIL */
117 -EIO
, /* BCME_RXFAIL */
118 -EINVAL
, /* BCME_NODEVICE */
119 -EINVAL
, /* BCME_NMODE_DISABLED */
120 -ENODATA
, /* BCME_NONRESIDENT */
122 /* When an new error code is added to bcmutils.h, add os
123 * spcecific error translation here as well
125 /* check if BCME_LAST changed since the last time this function was updated */
127 #error "You need to add a OS error translation in the linuxbcmerrormap \
128 for new error code defined in bcmutils.h"
132 /* translate bcmerrors into linux errors */
133 int osl_error(int bcmerror
)
137 else if (bcmerror
< BCME_LAST
)
138 bcmerror
= BCME_ERROR
;
140 /* Array bounds covered by ASSERT in osl_attach */
141 return linuxbcmerrormap
[-bcmerror
];
144 osl_t
*osl_attach(void *pdev
, uint bustype
, bool pkttag
)
148 osh
= kmalloc(sizeof(osl_t
), GFP_ATOMIC
);
151 bzero(osh
, sizeof(osl_t
));
153 /* Check that error map has the right number of entries in it */
154 ASSERT(ABS(BCME_LAST
) == (ARRAYSIZE(linuxbcmerrormap
) - 1));
156 osh
->magic
= OS_HANDLE_MAGIC
;
159 osh
->dbgmem_list
= NULL
;
161 osh
->pub
.pkttag
= pkttag
;
162 osh
->bustype
= bustype
;
168 osh
->pub
.mmbus
= TRUE
;
175 osh
->pub
.mmbus
= FALSE
;
182 #ifdef DHD_USE_STATIC_BUF
184 if (!bcm_static_buf
) {
185 if (!(bcm_static_buf
=
186 (bcm_static_buf_t
*) dhd_os_prealloc(3,
187 STATIC_BUF_SIZE
+ STATIC_BUF_TOTAL_LEN
))) {
188 printk(KERN_ERR
"can not alloc static buf!\n");
190 printk(KERN_ERR
"alloc static buf at %x!\n",
191 (unsigned int)bcm_static_buf
);
193 init_MUTEX(&bcm_static_buf
->static_sem
);
195 bcm_static_buf
->buf_ptr
=
196 (unsigned char *)bcm_static_buf
+ STATIC_BUF_SIZE
;
200 if (!bcm_static_skb
) {
202 void *skb_buff_ptr
= 0;
204 (bcm_static_pkt_t
*) ((char *)bcm_static_buf
+ 2048);
205 skb_buff_ptr
= dhd_os_prealloc(4, 0);
207 bcopy(skb_buff_ptr
, bcm_static_skb
,
208 sizeof(struct sk_buff
*) * 16);
209 for (i
= 0; i
< MAX_STATIC_PKT_NUM
* 2; i
++)
210 bcm_static_skb
->pkt_use
[i
] = 0;
212 init_MUTEX(&bcm_static_skb
->osl_pkt_sem
);
214 #endif /* DHD_USE_STATIC_BUF */
215 #if defined(BCMDBG) && !defined(BRCM_FULLMAC)
218 ASSERT(OSL_PKTTAG_SZ
<= sizeof(skb
->cb
));
224 void osl_detach(osl_t
*osh
)
229 #ifdef DHD_USE_STATIC_BUF
236 ASSERT(osh
->magic
== OS_HANDLE_MAGIC
);
240 /* Return a new packet. zero out pkttag */
241 void *BCMFASTPATH
osl_pktget(osl_t
*osh
, uint len
)
245 skb
= dev_alloc_skb(len
);
250 osh
->pub
.pktalloced
++;
256 /* Free the driver packet. Free the tag if present */
257 void BCMFASTPATH
osl_pktfree(osl_t
*osh
, void *p
, bool send
)
259 struct sk_buff
*skb
, *nskb
;
262 skb
= (struct sk_buff
*)p
;
265 if (send
&& osh
->pub
.tx_fn
)
266 osh
->pub
.tx_fn(osh
->pub
.tx_ctx
, p
, 0);
268 /* perversion: we use skb->next to chain multi-skb packets */
274 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
277 dev_kfree_skb_any(skb
);
279 /* can free immediately (even in_irq()) if destructor
284 osh
->pub
.pktalloced
--;
290 #ifdef DHD_USE_STATIC_BUF
291 void *osl_pktget_static(osl_t
*osh
, uint len
)
296 if (len
> (PAGE_SIZE
* 2)) {
297 printk(KERN_ERR
"Do we really need this big skb??\n");
298 return osl_pktget(osh
, len
);
301 down(&bcm_static_skb
->osl_pkt_sem
);
302 if (len
<= PAGE_SIZE
) {
303 for (i
= 0; i
< MAX_STATIC_PKT_NUM
; i
++) {
304 if (bcm_static_skb
->pkt_use
[i
] == 0)
308 if (i
!= MAX_STATIC_PKT_NUM
) {
309 bcm_static_skb
->pkt_use
[i
] = 1;
310 up(&bcm_static_skb
->osl_pkt_sem
);
312 skb
= bcm_static_skb
->skb_4k
[i
];
313 skb
->tail
= skb
->data
+ len
;
320 for (i
= 0; i
< MAX_STATIC_PKT_NUM
; i
++) {
321 if (bcm_static_skb
->pkt_use
[i
+ MAX_STATIC_PKT_NUM
] == 0)
325 if (i
!= MAX_STATIC_PKT_NUM
) {
326 bcm_static_skb
->pkt_use
[i
+ MAX_STATIC_PKT_NUM
] = 1;
327 up(&bcm_static_skb
->osl_pkt_sem
);
328 skb
= bcm_static_skb
->skb_8k
[i
];
329 skb
->tail
= skb
->data
+ len
;
335 up(&bcm_static_skb
->osl_pkt_sem
);
336 printk(KERN_ERR
"all static pkt in use!\n");
337 return osl_pktget(osh
, len
);
340 void osl_pktfree_static(osl_t
*osh
, void *p
, bool send
)
344 for (i
= 0; i
< MAX_STATIC_PKT_NUM
* 2; i
++) {
345 if (p
== bcm_static_skb
->skb_4k
[i
]) {
346 down(&bcm_static_skb
->osl_pkt_sem
);
347 bcm_static_skb
->pkt_use
[i
] = 0;
348 up(&bcm_static_skb
->osl_pkt_sem
);
353 return osl_pktfree(osh
, p
, send
);
355 #endif /* DHD_USE_STATIC_BUF */
356 uint32
osl_pci_read_config(osl_t
*osh
, uint offset
, uint size
)
359 uint retry
= PCI_CFG_RETRY
;
361 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
363 /* only 4byte access supported */
367 pci_read_config_dword(osh
->pdev
, offset
, &val
);
368 if (val
!= 0xffffffff)
373 if (retry
< PCI_CFG_RETRY
)
374 printk("PCI CONFIG READ access to %d required %d retries\n",
375 offset
, (PCI_CFG_RETRY
- retry
));
381 void osl_pci_write_config(osl_t
*osh
, uint offset
, uint size
, uint val
)
383 uint retry
= PCI_CFG_RETRY
;
385 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
387 /* only 4byte access supported */
391 pci_write_config_dword(osh
->pdev
, offset
, val
);
392 if (offset
!= PCI_BAR0_WIN
)
394 if (osl_pci_read_config(osh
, offset
, size
) == val
)
398 #if defined(BCMDBG) && !defined(BRCM_FULLMAC)
399 if (retry
< PCI_CFG_RETRY
)
400 printk("PCI CONFIG WRITE access to %d required %d retries\n",
401 offset
, (PCI_CFG_RETRY
- retry
));
405 /* return bus # for the pci device pointed by osh->pdev */
406 uint
osl_pci_bus(osl_t
*osh
)
408 ASSERT(osh
&& (osh
->magic
== OS_HANDLE_MAGIC
) && osh
->pdev
);
410 return ((struct pci_dev
*)osh
->pdev
)->bus
->number
;
413 /* return slot # for the pci device pointed by osh->pdev */
414 uint
osl_pci_slot(osl_t
*osh
)
416 ASSERT(osh
&& (osh
->magic
== OS_HANDLE_MAGIC
) && osh
->pdev
);
418 return PCI_SLOT(((struct pci_dev
*)osh
->pdev
)->devfn
);
422 osl_pcmcia_attr(osl_t
*osh
, uint offset
, char *buf
, int size
, bool write
)
426 void osl_pcmcia_read_attr(osl_t
*osh
, uint offset
, void *buf
, int size
)
428 osl_pcmcia_attr(osh
, offset
, (char *)buf
, size
, FALSE
);
431 void osl_pcmcia_write_attr(osl_t
*osh
, uint offset
, void *buf
, int size
)
433 osl_pcmcia_attr(osh
, offset
, (char *)buf
, size
, TRUE
);
436 void *osl_malloc(osl_t
*osh
, uint size
)
440 /* only ASSERT if osh is defined */
442 ASSERT(osh
->magic
== OS_HANDLE_MAGIC
);
444 #ifdef DHD_USE_STATIC_BUF
445 if (bcm_static_buf
) {
447 if ((size
>= PAGE_SIZE
) && (size
<= STATIC_BUF_SIZE
)) {
448 down(&bcm_static_buf
->static_sem
);
449 for (i
= 0; i
< MAX_STATIC_BUF_NUM
; i
++) {
450 if (bcm_static_buf
->buf_use
[i
] == 0)
453 if (i
== MAX_STATIC_BUF_NUM
) {
454 up(&bcm_static_buf
->static_sem
);
455 printk(KERN_ERR
"all static buff in use!\n");
458 bcm_static_buf
->buf_use
[i
] = 1;
459 up(&bcm_static_buf
->static_sem
);
461 bzero(bcm_static_buf
->buf_ptr
+ STATIC_BUF_SIZE
* i
,
464 osh
->malloced
+= size
;
466 return (void *)(bcm_static_buf
->buf_ptr
+
467 STATIC_BUF_SIZE
* i
);
471 #endif /* DHD_USE_STATIC_BUF */
473 addr
= kmalloc(size
, GFP_ATOMIC
);
480 osh
->malloced
+= size
;
485 void osl_mfree(osl_t
*osh
, void *addr
, uint size
)
487 #ifdef DHD_USE_STATIC_BUF
488 if (bcm_static_buf
) {
489 if ((addr
> (void *)bcm_static_buf
) && ((unsigned char *)addr
490 <= ((unsigned char *)
492 STATIC_BUF_TOTAL_LEN
))) {
495 ((unsigned char *)addr
-
496 bcm_static_buf
->buf_ptr
) / STATIC_BUF_SIZE
;
497 down(&bcm_static_buf
->static_sem
);
498 bcm_static_buf
->buf_use
[buf_idx
] = 0;
499 up(&bcm_static_buf
->static_sem
);
502 ASSERT(osh
->magic
== OS_HANDLE_MAGIC
);
503 osh
->malloced
-= size
;
508 #endif /* DHD_USE_STATIC_BUF */
510 ASSERT(osh
->magic
== OS_HANDLE_MAGIC
);
511 osh
->malloced
-= size
;
516 uint
osl_malloced(osl_t
*osh
)
518 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
519 return osh
->malloced
;
522 uint
osl_malloc_failed(osl_t
*osh
)
524 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
528 uint
osl_dma_consistent_align(void)
534 void *osl_dma_alloc_consistent(osl_t
*osh
, uint size
, unsigned long *pap
)
536 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
538 return pci_alloc_consistent(osh
->pdev
, size
, (dma_addr_t
*) pap
);
540 #else /* !BRCM_FULLMAC */
541 void *osl_dma_alloc_consistent(osl_t
*osh
, uint size
, uint16 align_bits
,
542 uint
*alloced
, unsigned long *pap
)
544 uint16 align
= (1 << align_bits
);
545 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
547 if (!ISALIGNED(DMA_CONSISTENT_ALIGN
, align
))
551 return pci_alloc_consistent(osh
->pdev
, size
, (dma_addr_t
*) pap
);
553 #endif /* BRCM_FULLMAC */
555 void osl_dma_free_consistent(osl_t
*osh
, void *va
, uint size
, unsigned long pa
)
557 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
559 pci_free_consistent(osh
->pdev
, size
, va
, (dma_addr_t
) pa
);
562 uint BCMFASTPATH
osl_dma_map(osl_t
*osh
, void *va
, uint size
, int direction
)
566 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
567 dir
= (direction
== DMA_TX
) ? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE
;
568 return pci_map_single(osh
->pdev
, va
, size
, dir
);
571 void BCMFASTPATH
osl_dma_unmap(osl_t
*osh
, uint pa
, uint size
, int direction
)
575 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
576 dir
= (direction
== DMA_TX
) ? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE
;
577 pci_unmap_single(osh
->pdev
, (uint32
) pa
, size
, dir
);
580 #if defined(BCMDBG_ASSERT)
581 void osl_assert(char *exp
, char *file
, int line
)
586 basename
= strrchr(file
, '/');
595 snprintf(tempbuf
, 256,
596 "assertion \"%s\" failed: file \"%s\", line %d\n", exp
,
599 /* Print assert message and give it time to be written to /var/log/messages */
600 if (!in_interrupt()) {
602 printk(KERN_ERR
"%s", tempbuf
);
603 printk(KERN_ERR
"panic in %d seconds\n", delay
);
604 set_current_state(TASK_INTERRUPTIBLE
);
605 schedule_timeout(delay
* HZ
);
608 switch (g_assert_type
) {
610 panic(KERN_ERR
"%s", tempbuf
);
613 printk(KERN_ERR
"%s", tempbuf
);
617 printk(KERN_ERR
"%s", tempbuf
);
622 #endif /* BCMDBG_ASSERT */
625 #endif /* defined(BCMDBG_ASSERT) */
627 void osl_delay(uint usec
)
639 * The pkttag contents are NOT cloned.
641 void *osl_pktdup(osl_t
*osh
, void *skb
)
645 p
= skb_clone((struct sk_buff
*)skb
, GFP_ATOMIC
);
649 /* skb_clone copies skb->cb.. we don't want that */
651 bzero((void *)((struct sk_buff
*)p
)->cb
, OSL_PKTTAG_SZ
);
653 /* Increment the packet counter */
654 osh
->pub
.pktalloced
++;
658 #if defined(BCMSDIO) && !defined(BRCM_FULLMAC)
659 u8
osl_readb(osl_t
*osh
, volatile u8
*r
)
661 osl_rreg_fn_t rreg
= ((osl_pubinfo_t
*) osh
)->rreg_fn
;
662 void *ctx
= ((osl_pubinfo_t
*) osh
)->reg_ctx
;
664 return (u8
) ((rreg
) (ctx
, (void *)r
, sizeof(u8
)));
667 uint16
osl_readw(osl_t
*osh
, volatile uint16
*r
)
669 osl_rreg_fn_t rreg
= ((osl_pubinfo_t
*) osh
)->rreg_fn
;
670 void *ctx
= ((osl_pubinfo_t
*) osh
)->reg_ctx
;
672 return (uint16
) ((rreg
) (ctx
, (void *)r
, sizeof(uint16
)));
675 uint32
osl_readl(osl_t
*osh
, volatile uint32
*r
)
677 osl_rreg_fn_t rreg
= ((osl_pubinfo_t
*) osh
)->rreg_fn
;
678 void *ctx
= ((osl_pubinfo_t
*) osh
)->reg_ctx
;
680 return (uint32
) ((rreg
) (ctx
, (void *)r
, sizeof(uint32
)));
683 void osl_writeb(osl_t
*osh
, volatile u8
*r
, u8 v
)
685 osl_wreg_fn_t wreg
= ((osl_pubinfo_t
*) osh
)->wreg_fn
;
686 void *ctx
= ((osl_pubinfo_t
*) osh
)->reg_ctx
;
688 ((wreg
) (ctx
, (void *)r
, v
, sizeof(u8
)));
691 void osl_writew(osl_t
*osh
, volatile uint16
*r
, uint16 v
)
693 osl_wreg_fn_t wreg
= ((osl_pubinfo_t
*) osh
)->wreg_fn
;
694 void *ctx
= ((osl_pubinfo_t
*) osh
)->reg_ctx
;
696 ((wreg
) (ctx
, (void *)r
, v
, sizeof(uint16
)));
699 void osl_writel(osl_t
*osh
, volatile uint32
*r
, uint32 v
)
701 osl_wreg_fn_t wreg
= ((osl_pubinfo_t
*) osh
)->wreg_fn
;
702 void *ctx
= ((osl_pubinfo_t
*) osh
)->reg_ctx
;
704 ((wreg
) (ctx
, (void *)r
, v
, sizeof(uint32
)));
707 /* Linux Kernel: File Operations: end */
This page took 0.048302 seconds and 5 git commands to generate.