2 * Linux OS Independent Layer
4 * Copyright 2007, Broadcom Corporation
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
18 #include <bcmendian.h>
22 #include "linux_osl.h"
24 #include <linux/delay.h>
26 #include <asm/paccess.h>
30 #define PCI_CFG_RETRY 10
32 #define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */
33 #define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */
35 typedef struct bcm_mem_link
37 struct bcm_mem_link
*prev
;
38 struct bcm_mem_link
*next
;
41 char file
[BCM_MEM_FILENAME_LEN
];
53 bcm_mem_link_t
*dbgmem_list
;
54 #ifdef BCMDBG_PKT /* pkt logging for debugging */
55 pktlist_info_t pktlist
;
56 #endif /* BCMDBG_PKT */
60 static int16 linuxbcmerrormap
[] = { 0, /* 0 */
61 -EINVAL
, /* BCME_ERROR */
62 -EINVAL
, /* BCME_BADARG */
63 -EINVAL
, /* BCME_BADOPTION */
64 -EINVAL
, /* BCME_NOTUP */
65 -EINVAL
, /* BCME_NOTDOWN */
66 -EINVAL
, /* BCME_NOTAP */
67 -EINVAL
, /* BCME_NOTSTA */
68 -EINVAL
, /* BCME_BADKEYIDX */
69 -EINVAL
, /* BCME_RADIOOFF */
70 -EINVAL
, /* BCME_NOTBANDLOCKED */
71 -EINVAL
, /* BCME_NOCLK */
72 -EINVAL
, /* BCME_BADRATESET */
73 -EINVAL
, /* BCME_BADBAND */
74 -E2BIG
, /* BCME_BUFTOOSHORT */
75 -E2BIG
, /* BCME_BUFTOOLONG */
76 -EBUSY
, /* BCME_BUSY */
77 -EINVAL
, /* BCME_NOTASSOCIATED */
78 -EINVAL
, /* BCME_BADSSIDLEN */
79 -EINVAL
, /* BCME_OUTOFRANGECHAN */
80 -EINVAL
, /* BCME_BADCHAN */
81 -EFAULT
, /* BCME_BADADDR */
82 -ENOMEM
, /* BCME_NORESOURCE */
83 -EOPNOTSUPP
, /* BCME_UNSUPPORTED */
84 -EMSGSIZE
, /* BCME_BADLENGTH */
85 -EINVAL
, /* BCME_NOTREADY */
86 -EPERM
, /* BCME_NOTPERMITTED */
87 -ENOMEM
, /* BCME_NOMEM */
88 -EINVAL
, /* BCME_ASSOCIATED */
89 -ERANGE
, /* BCME_RANGE */
90 -EINVAL
, /* BCME_NOTFOUND */
91 -EINVAL
, /* BCME_WME_NOT_ENABLED */
92 -EINVAL
, /* BCME_TSPEC_NOTFOUND */
93 -EINVAL
, /* BCME_ACM_NOTSUPPORTED */
94 -EINVAL
, /* BCME_NOT_WME_ASSOCIATION */
95 -EIO
, /* BCME_SDIO_ERROR */
96 -ENODEV
, /* BCME_DONGLE_DOWN */
97 -EINVAL
/* BCME_VERSION */
98 /* When an new error code is added to bcmutils.h, add os
99 * spcecific error translation here as well
101 /* check if BCME_LAST changed since the last time this function was updated */
103 #error "You need to add a OS error translation in the linuxbcmerrormap \
104 for new error code defined in bcmuitls.h"
105 #endif /* BCME_LAST != -37 */
108 /* translate bcmerrors into linux errors */
110 osl_error (int bcmerror
)
114 else if (bcmerror
< BCME_LAST
)
115 bcmerror
= BCME_ERROR
;
117 /* Array bounds covered by ASSERT in osl_attach */
118 return linuxbcmerrormap
[-bcmerror
];
122 osl_attach (void *pdev
, uint bustype
, bool pkttag
)
126 osh
= kmalloc (sizeof (osl_t
), GFP_ATOMIC
);
129 bzero (osh
, sizeof (osl_t
));
131 /* Check that error map has the right number of entries in it */
132 ASSERT (ABS (BCME_LAST
) == (ARRAYSIZE (linuxbcmerrormap
) - 1));
134 osh
->magic
= OS_HANDLE_MAGIC
;
137 osh
->dbgmem_list
= NULL
;
139 osh
->pub
.pkttag
= pkttag
;
140 osh
->bustype
= bustype
;
147 osh
->pub
.mmbus
= TRUE
;
161 ASSERT (OSL_PKTTAG_SZ
<= sizeof (skb
->cb
));
168 osl_detach (osl_t
* osh
)
173 ASSERT (osh
->magic
== OS_HANDLE_MAGIC
);
177 /* Return a new packet. zero out pkttag */
179 osl_pktget (osl_t
* osh
, uint len
)
183 if ((skb
= dev_alloc_skb (len
)))
189 pktlist_add (&(osh
->pktlist
), (void *) skb
);
190 #endif /* BCMDBG_PKT */
192 osh
->pub
.pktalloced
++;
195 return ((void *) skb
);
198 /* Free the driver packet. Free the tag if present */
200 osl_pktfree (osl_t
* osh
, void *p
, bool send
)
202 struct sk_buff
*skb
, *nskb
;
204 skb
= (struct sk_buff
*) p
;
206 if (send
&& osh
->pub
.tx_fn
)
207 osh
->pub
.tx_fn (osh
->pub
.tx_ctx
, p
, 0);
209 /* perversion: we use skb->next to chain multi-skb packets */
216 pktlist_remove (&(osh
->pktlist
), (void *) skb
);
217 #endif /* BCMDBG_PKT */
221 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists
223 dev_kfree_skb_any (skb
);
227 /* can free immediately (even in_irq()) if destructor does not exist */
231 osh
->pub
.pktalloced
--;
238 osl_pci_read_config (osl_t
* osh
, uint offset
, uint size
)
241 uint retry
= PCI_CFG_RETRY
;
243 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
245 /* only 4byte access supported */
250 pci_read_config_dword (osh
->pdev
, offset
, &val
);
251 if (val
!= 0xffffffff)
257 if (retry
< PCI_CFG_RETRY
)
258 printk ("PCI CONFIG READ access to %d required %d retries\n", offset
,
259 (PCI_CFG_RETRY
- retry
));
266 osl_pci_write_config (osl_t
* osh
, uint offset
, uint size
, uint val
)
268 uint retry
= PCI_CFG_RETRY
;
270 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
272 /* only 4byte access supported */
277 pci_write_config_dword (osh
->pdev
, offset
, val
);
278 if (offset
!= PCI_BAR0_WIN
)
280 if (osl_pci_read_config (osh
, offset
, size
) == val
)
286 if (retry
< PCI_CFG_RETRY
)
287 printk ("PCI CONFIG WRITE access to %d required %d retries\n", offset
,
288 (PCI_CFG_RETRY
- retry
));
292 /* return bus # for the pci device pointed by osh->pdev */
294 osl_pci_bus (osl_t
* osh
)
296 ASSERT (osh
&& (osh
->magic
== OS_HANDLE_MAGIC
) && osh
->pdev
);
298 return ((struct pci_dev
*) osh
->pdev
)->bus
->number
;
301 /* return slot # for the pci device pointed by osh->pdev */
303 osl_pci_slot (osl_t
* osh
)
305 ASSERT (osh
&& (osh
->magic
== OS_HANDLE_MAGIC
) && osh
->pdev
);
307 return PCI_SLOT (((struct pci_dev
*) osh
->pdev
)->devfn
);
311 osl_pcmcia_attr (osl_t
* osh
, uint offset
, char *buf
, int size
, bool write
)
316 osl_pcmcia_read_attr (osl_t
* osh
, uint offset
, void *buf
, int size
)
318 osl_pcmcia_attr (osh
, offset
, (char *) buf
, size
, FALSE
);
322 osl_pcmcia_write_attr (osl_t
* osh
, uint offset
, void *buf
, int size
)
324 osl_pcmcia_attr (osh
, offset
, (char *) buf
, size
, TRUE
);
331 osl_debug_malloc (osl_t
* osh
, uint size
, int line
, char *file
)
339 (bcm_mem_link_t
*) osl_malloc (osh
,
340 sizeof (bcm_mem_link_t
) + size
)) ==
347 basename
= strrchr (file
, '/');
355 strncpy (p
->file
, basename
, BCM_MEM_FILENAME_LEN
);
356 p
->file
[BCM_MEM_FILENAME_LEN
- 1] = '\0';
358 /* link this block */
360 p
->next
= osh
->dbgmem_list
;
363 osh
->dbgmem_list
= p
;
369 osl_debug_mfree (osl_t
* osh
, void *addr
, uint size
, int line
, char *file
)
372 (bcm_mem_link_t
*) ((int8
*) addr
- sizeof (bcm_mem_link_t
));
374 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
379 ("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n",
380 addr
, size
, line
, file
);
388 ("osl_debug_mfree: dealloc size %d does not match alloc size %d on addr %p"
389 " at line %d file %s\n", size
, p
->size
, addr
, line
, file
);
390 ASSERT (p
->size
== size
);
394 /* unlink this block */
396 p
->prev
->next
= p
->next
;
398 p
->next
->prev
= p
->prev
;
399 if (osh
->dbgmem_list
== p
)
400 osh
->dbgmem_list
= p
->next
;
401 p
->next
= p
->prev
= NULL
;
403 osl_mfree (osh
, p
, size
+ sizeof (bcm_mem_link_t
));
407 osl_debug_memdump (osl_t
* osh
, struct bcmstrbuf
*b
)
411 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
413 bcm_bprintf (b
, " Address\tSize\tFile:line\n");
414 for (p
= osh
->dbgmem_list
; p
; p
= p
->next
)
415 bcm_bprintf (b
, "0x%08x\t%5d\t%s:%d\n",
416 (uintptr
) p
+ sizeof (bcm_mem_link_t
), p
->size
, p
->file
,
422 #endif /* BCMDBG_MEM */
425 osl_malloc (osl_t
* osh
, uint size
)
429 /* only ASSERT if osh is defined */
431 ASSERT (osh
->magic
== OS_HANDLE_MAGIC
);
433 if ((addr
= kmalloc (size
, GFP_ATOMIC
)) == NULL
)
440 osh
->malloced
+= size
;
446 osl_mfree (osl_t
* osh
, void *addr
, uint size
)
450 ASSERT (osh
->magic
== OS_HANDLE_MAGIC
);
451 osh
->malloced
-= size
;
457 osl_malloced (osl_t
* osh
)
459 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
460 return (osh
->malloced
);
464 osl_malloc_failed (osl_t
* osh
)
466 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
467 return (osh
->failed
);
471 osl_dma_alloc_consistent (osl_t
* osh
, uint size
, ulong
* pap
)
473 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
475 return (pci_alloc_consistent (osh
->pdev
, size
, (dma_addr_t
*) pap
));
479 osl_dma_free_consistent (osl_t
* osh
, void *va
, uint size
, ulong pa
)
481 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
483 pci_free_consistent (osh
->pdev
, size
, va
, (dma_addr_t
) pa
);
487 osl_dma_map (osl_t
* osh
, void *va
, uint size
, int direction
)
491 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
492 dir
= (direction
== DMA_TX
) ? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE
;
493 return (pci_map_single (osh
->pdev
, va
, size
, dir
));
497 osl_dma_unmap (osl_t
* osh
, uint pa
, uint size
, int direction
)
501 ASSERT ((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
502 dir
= (direction
== DMA_TX
) ? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE
;
503 pci_unmap_single (osh
->pdev
, (uint32
) pa
, size
, dir
);
506 #if defined(BINOSL) || defined(BCMDBG_ASSERT)
508 osl_assert (char *exp
, char *file
, int line
)
512 sprintf (tempbuf
, "assertion \"%s\" failed: file \"%s\", line %d\n", exp
,
516 #endif /* BCMDBG_ASSERT || BINOSL */
519 osl_delay (uint usec
)
525 d
= MIN (usec
, 1000);
532 * The pkttag contents are NOT cloned.
535 osl_pktdup (osl_t
* osh
, void *skb
)
539 if ((p
= skb_clone ((struct sk_buff
*) skb
, GFP_ATOMIC
)) == NULL
)
542 /* skb_clone copies skb->cb.. we don't want that */
544 bzero ((void *) ((struct sk_buff
*) p
)->cb
, OSL_PKTTAG_SZ
);
546 /* Increment the packet counter */
547 osh
->pub
.pktalloced
++;
549 pktlist_add (&(osh
->pktlist
), (void *) p
);
550 #endif /* BCMDBG_PKT */
555 osl_pktalloced (osl_t
* osh
)
557 return (osh
->pub
.pktalloced
);
562 osl_pktlist_dump (osl_t
* osh
, char *buf
)
564 pktlist_dump (&(osh
->pktlist
), buf
);
569 osl_pktlist_add (osl_t
* osh
, void *p
)
571 pktlist_add (&(osh
->pktlist
), p
);
575 osl_pktlist_remove (osl_t
* osh
, void *p
)
577 pktlist_remove (&(osh
->pktlist
), p
);
579 #endif /* BCMDBG_PKT */
582 * BINOSL selects the slightly slower function-call-based binary compatible osl.
587 osl_printf (const char *format
, ...)
593 /* sprintf into a local buffer because there *is* no "vprintk()".. */
594 va_start (args
, format
);
595 len
= vsnprintf (buf
, 1024, format
, args
);
598 if (len
> sizeof (buf
))
600 printk ("osl_printf: buffer overrun\n");
604 return (printk (buf
));
608 osl_sprintf (char *buf
, const char *format
, ...)
613 va_start (args
, format
);
614 rc
= vsprintf (buf
, format
, args
);
620 osl_strcmp (const char *s1
, const char *s2
)
622 return (strcmp (s1
, s2
));
626 osl_strncmp (const char *s1
, const char *s2
, uint n
)
628 return (strncmp (s1
, s2
, n
));
632 osl_strlen (const char *s
)
638 osl_strcpy (char *d
, const char *s
)
640 return (strcpy (d
, s
));
644 osl_strncpy (char *d
, const char *s
, uint n
)
646 return (strncpy (d
, s
, n
));
650 bcopy (const void *src
, void *dst
, int len
)
652 memcpy (dst
, src
, len
);
656 bcmp (const void *b1
, const void *b2
, int len
)
658 return (memcmp (b1
, b2
, len
));
662 bzero (void *b
, int len
)
664 memset (b
, '\0', len
);
668 osl_readl (volatile uint32
* r
)
674 osl_readw (volatile uint16
* r
)
680 osl_readb (volatile uint8
* r
)
686 osl_writel (uint32 v
, volatile uint32
* r
)
692 osl_writew (uint16 v
, volatile uint16
* r
)
698 osl_writeb (uint8 v
, volatile uint8
* r
)
704 osl_uncached (void *va
)
707 return ((void *) KSEG1ADDR (va
));
709 return ((void *) va
);
719 cycles
= read_c0_count () * 2;
720 #elif defined(__i386__)
724 #endif /* defined(mips) */
729 osl_reg_map (uint32 pa
, uint size
)
731 return (ioremap_nocache ((unsigned long) pa
, (unsigned long) size
));
735 osl_reg_unmap (void *va
)
741 osl_busprobe (uint32
* val
, uint32 addr
)
744 return get_dbe (*val
, (uint32
*) addr
);
746 *val
= readl ((uint32
*) (uintptr
) addr
);
752 osl_pktshared (void *skb
)
754 return (((struct sk_buff
*) skb
)->cloned
);
758 osl_pktdata (osl_t
* osh
, void *skb
)
760 return (((struct sk_buff
*) skb
)->data
);
764 osl_pktlen (osl_t
* osh
, void *skb
)
766 return (((struct sk_buff
*) skb
)->len
);
770 osl_pktheadroom (osl_t
* osh
, void *skb
)
772 return (uint
) skb_headroom ((struct sk_buff
*) skb
);
776 osl_pkttailroom (osl_t
* osh
, void *skb
)
778 return (uint
) skb_tailroom ((struct sk_buff
*) skb
);
782 osl_pktnext (osl_t
* osh
, void *skb
)
784 return (((struct sk_buff
*) skb
)->next
);
788 osl_pktsetnext (void *skb
, void *x
)
790 ((struct sk_buff
*) skb
)->next
= (struct sk_buff
*) x
;
794 osl_pktsetlen (osl_t
* osh
, void *skb
, uint len
)
796 __skb_trim ((struct sk_buff
*) skb
, len
);
800 osl_pktpush (osl_t
* osh
, void *skb
, int bytes
)
802 return (skb_push ((struct sk_buff
*) skb
, bytes
));
806 osl_pktpull (osl_t
* osh
, void *skb
, int bytes
)
808 return (skb_pull ((struct sk_buff
*) skb
, bytes
));
812 osl_pkttag (void *skb
)
814 return ((void *) (((struct sk_buff
*) skb
)->cb
));
818 osl_pktlink (void *skb
)
820 return (((struct sk_buff
*) skb
)->prev
);
824 osl_pktsetlink (void *skb
, void *x
)
826 ((struct sk_buff
*) skb
)->prev
= (struct sk_buff
*) x
;
830 osl_pktprio (void *skb
)
832 return (((struct sk_buff
*) skb
)->priority
);
836 osl_pktsetprio (void *skb
, uint x
)
838 ((struct sk_buff
*) skb
)->priority
= x
;
841 /* Convert a driver packet to native(OS) packet
842 * In the process, packettag is zeroed out before sending up
843 * IP code depends on skb->cb to be setup correctly with various options
844 * In our case, that means it should be 0
847 osl_pkt_tonative (osl_t
* osh
, void *pkt
)
849 struct sk_buff
*nskb
;
852 bzero ((void *) ((struct sk_buff
*) pkt
)->cb
, OSL_PKTTAG_SZ
);
854 /* Decrement the packet counter */
855 for (nskb
= (struct sk_buff
*) pkt
; nskb
; nskb
= nskb
->next
)
858 pktlist_remove (&(osh
->pktlist
), (void *) nskb
);
859 #endif /* BCMDBG_PKT */
860 osh
->pub
.pktalloced
--;
863 return (struct sk_buff
*) pkt
;
866 /* Convert a native(OS) packet to driver packet.
867 * In the process, native packet is destroyed, there is no copying
868 * Also, a packettag is zeroed out
871 osl_pkt_frmnative (osl_t
* osh
, struct sk_buff
*skb
)
873 struct sk_buff
*nskb
;
876 bzero ((void *) skb
->cb
, OSL_PKTTAG_SZ
);
878 /* Increment the packet counter */
879 for (nskb
= skb
; nskb
; nskb
= nskb
->next
)
882 pktlist_add (&(osh
->pktlist
), (void *) nskb
);
883 #endif /* BCMDBG_PKT */
884 osh
->pub
.pktalloced
++;