2 * Linux OS Independent Layer
4 * Copyright 2004, 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>
23 #include <linux/delay.h>
25 #include <asm/paccess.h>
29 #define PCI_CFG_RETRY 10
31 #define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */
32 #define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */
34 typedef struct bcm_mem_link
{
35 struct bcm_mem_link
*prev
;
36 struct bcm_mem_link
*next
;
39 char file
[BCM_MEM_FILENAME_LEN
];
49 bcm_mem_link_t
*dbgmem_list
;
50 #if defined(DSLCPE_DELAY)
51 shared_osl_t
*oshsh
; /* osh shared */
53 #ifdef BCMDBG_PKT /* pkt logging for debugging */
54 pktlist_info_t pktlist
;
55 #endif /* BCMDBG_PKT */
58 static int16 linuxbcmerrormap
[] = \
60 -EINVAL
, /* BCME_ERROR */
61 -EINVAL
, /* BCME_BADARG */
62 -EINVAL
, /* BCME_BADOPTION */
63 -EINVAL
, /* BCME_NOTUP */
64 -EINVAL
, /* BCME_NOTDOWN */
65 -EINVAL
, /* BCME_NOTAP */
66 -EINVAL
, /* BCME_NOTSTA */
67 -EINVAL
, /* BCME_BADKEYIDX */
68 -EINVAL
, /* BCME_RADIOOFF */
69 -EINVAL
, /* BCME_NOTBANDLOCKED */
70 -EINVAL
, /* BCME_NOCLK */
71 -EINVAL
, /* BCME_BADRATESET */
72 -EINVAL
, /* BCME_BADBAND */
73 -E2BIG
, /* BCME_BUFTOOSHORT */
74 -E2BIG
, /* BCME_BUFTOOLONG */
75 -EBUSY
, /* BCME_BUSY */
76 -EINVAL
, /* BCME_NOTASSOCIATED */
77 -EINVAL
, /* BCME_BADSSIDLEN */
78 -EINVAL
, /* BCME_OUTOFRANGECHAN */
79 -EINVAL
, /* BCME_BADCHAN */
80 -EFAULT
, /* BCME_BADADDR */
81 -ENOMEM
, /* BCME_NORESOURCE */
82 -EOPNOTSUPP
, /* BCME_UNSUPPORTED */
83 -EMSGSIZE
, /* BCME_BADLENGTH */
84 -EINVAL
, /* BCME_NOTREADY */
85 -EPERM
, /* BCME_NOTPERMITTED */
86 -ENOMEM
, /* BCME_NOMEM */
87 -EINVAL
, /* BCME_ASSOCIATED */
88 -ERANGE
, /* BCME_RANGE */
89 -EINVAL
, /* BCME_NOTFOUND */
90 -EINVAL
, /* BCME_WME_NOT_ENABLED */
91 -EINVAL
, /* BCME_TSPEC_NOTFOUND */
92 -EINVAL
, /* BCME_ACM_NOTSUPPORTED */
93 -EINVAL
, /* BCME_NOT_WME_ASSOCIATION */
94 -EIO
, /* BCME_SDIO_ERROR */
95 -ENODEV
, /* BCME_DONGLE_DOWN */
96 -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
;
146 osh
->pub
.mmbus
= TRUE
;
151 osh
->pub
.mmbus
= FALSE
;
162 osl_detach(osl_t
*osh
)
167 ASSERT(osh
->magic
== OS_HANDLE_MAGIC
);
171 /* Return a new packet. zero out pkttag */
173 osl_pktget(osl_t
*osh
, uint len
)
177 if ((skb
= dev_alloc_skb(len
))) {
182 pktlist_add(&(osh
->pktlist
), (void *) skb
);
183 #endif /* BCMDBG_PKT */
185 osh
->pub
.pktalloced
++;
188 return ((void*) skb
);
191 /* Free the driver packet. Free the tag if present */
193 osl_pktfree(osl_t
*osh
, void *p
, bool send
)
195 struct sk_buff
*skb
, *nskb
;
197 skb
= (struct sk_buff
*) p
;
199 if (send
&& osh
->pub
.tx_fn
)
200 osh
->pub
.tx_fn(osh
->pub
.tx_ctx
, p
, 0);
202 /* perversion: we use skb->next to chain multi-skb packets */
208 pktlist_remove(&(osh
->pktlist
), (void *) skb
);
209 #endif /* BCMDBG_PKT */
211 if (skb
->destructor
) {
212 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists
214 dev_kfree_skb_any(skb
);
216 /* can free immediately (even in_irq()) if destructor does not exist */
220 osh
->pub
.pktalloced
--;
227 osl_pci_read_config(osl_t
*osh
, uint offset
, uint size
)
230 uint retry
= PCI_CFG_RETRY
;
232 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
234 /* only 4byte access supported */
238 pci_read_config_dword(osh
->pdev
, offset
, &val
);
239 if (val
!= 0xffffffff)
248 osl_pci_write_config(osl_t
*osh
, uint offset
, uint size
, uint val
)
250 uint retry
= PCI_CFG_RETRY
;
252 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
254 /* only 4byte access supported */
258 pci_write_config_dword(osh
->pdev
, offset
, val
);
259 if (offset
!= PCI_BAR0_WIN
)
261 if (osl_pci_read_config(osh
, offset
, size
) == val
)
267 /* return bus # for the pci device pointed by osh->pdev */
269 osl_pci_bus(osl_t
*osh
)
271 ASSERT(osh
&& (osh
->magic
== OS_HANDLE_MAGIC
) && osh
->pdev
);
273 return ((struct pci_dev
*)osh
->pdev
)->bus
->number
;
276 /* return slot # for the pci device pointed by osh->pdev */
278 osl_pci_slot(osl_t
*osh
)
280 ASSERT(osh
&& (osh
->magic
== OS_HANDLE_MAGIC
) && osh
->pdev
);
282 return PCI_SLOT(((struct pci_dev
*)osh
->pdev
)->devfn
);
286 osl_pcmcia_attr(osl_t
*osh
, uint offset
, char *buf
, int size
, bool write
)
291 osl_pcmcia_read_attr(osl_t
*osh
, uint offset
, void *buf
, int size
)
293 osl_pcmcia_attr(osh
, offset
, (char *) buf
, size
, FALSE
);
297 osl_pcmcia_write_attr(osl_t
*osh
, uint offset
, void *buf
, int size
)
299 osl_pcmcia_attr(osh
, offset
, (char *) buf
, size
, TRUE
);
306 osl_debug_malloc(osl_t
*osh
, uint size
, int line
, char* file
)
313 if ((p
= (bcm_mem_link_t
*)osl_malloc(osh
, sizeof(bcm_mem_link_t
) + size
)) == NULL
)
319 basename
= strrchr(file
, '/');
327 strncpy(p
->file
, basename
, BCM_MEM_FILENAME_LEN
);
328 p
->file
[BCM_MEM_FILENAME_LEN
- 1] = '\0';
330 /* link this block */
332 p
->next
= osh
->dbgmem_list
;
335 osh
->dbgmem_list
= p
;
341 osl_debug_mfree(osl_t
*osh
, void *addr
, uint size
, int line
, char* file
)
343 bcm_mem_link_t
*p
= (bcm_mem_link_t
*)((int8
*)addr
- sizeof(bcm_mem_link_t
));
345 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
348 printk("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n",
349 addr
, size
, line
, file
);
354 if (p
->size
!= size
) {
355 printk("osl_debug_mfree: dealloc size %d does not match alloc size %d on addr %p"
356 " at line %d file %s\n",
357 size
, p
->size
, addr
, line
, file
);
358 ASSERT(p
->size
== size
);
362 /* unlink this block */
364 p
->prev
->next
= p
->next
;
366 p
->next
->prev
= p
->prev
;
367 if (osh
->dbgmem_list
== p
)
368 osh
->dbgmem_list
= p
->next
;
369 p
->next
= p
->prev
= NULL
;
371 osl_mfree(osh
, p
, size
+ sizeof(bcm_mem_link_t
));
375 osl_debug_memdump(osl_t
*osh
, struct bcmstrbuf
*b
)
379 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
381 bcm_bprintf(b
, " Address\tSize\tFile:line\n");
382 for (p
= osh
->dbgmem_list
; p
; p
= p
->next
)
383 bcm_bprintf(b
, "0x%08x\t%5d\t%s:%d\n",
384 (uintptr
)p
+ sizeof(bcm_mem_link_t
), p
->size
, p
->file
, p
->line
);
389 #endif /* BCMDBG_MEM */
392 osl_malloc(osl_t
*osh
, uint size
)
396 /* only ASSERT if osh is defined */
398 ASSERT(osh
->magic
== OS_HANDLE_MAGIC
);
400 if ((addr
= kmalloc(size
, GFP_ATOMIC
)) == NULL
) {
406 osh
->malloced
+= size
;
412 osl_mfree(osl_t
*osh
, void *addr
, uint size
)
415 ASSERT(osh
->magic
== OS_HANDLE_MAGIC
);
416 osh
->malloced
-= size
;
422 osl_malloced(osl_t
*osh
)
424 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
425 return (osh
->malloced
);
429 osl_malloc_failed(osl_t
*osh
)
431 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
432 return (osh
->failed
);
436 osl_dma_alloc_consistent(osl_t
*osh
, uint size
, ulong
*pap
)
438 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
440 return (pci_alloc_consistent(osh
->pdev
, size
, (dma_addr_t
*)pap
));
444 osl_dma_free_consistent(osl_t
*osh
, void *va
, uint size
, ulong pa
)
446 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
448 pci_free_consistent(osh
->pdev
, size
, va
, (dma_addr_t
)pa
);
452 osl_dma_map(osl_t
*osh
, void *va
, uint size
, int direction
)
456 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
457 dir
= (direction
== DMA_TX
)? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE
;
458 return (pci_map_single(osh
->pdev
, va
, size
, dir
));
462 osl_dma_unmap(osl_t
*osh
, uint pa
, uint size
, int direction
)
466 ASSERT((osh
&& (osh
->magic
== OS_HANDLE_MAGIC
)));
467 dir
= (direction
== DMA_TX
)? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE
;
468 pci_unmap_single(osh
->pdev
, (uint32
)pa
, size
, dir
);
471 #if defined(BINOSL) || defined(CONFIG_BCMDBG_ASSERT)
473 osl_assert(char *exp
, char *file
, int line
)
477 sprintf(tempbuf
, "assertion \"%s\" failed: file \"%s\", line %d\n", exp
, file
, line
);
480 #endif /* BCMDBG_ASSERT || BINOSL */
494 #if defined(DSLCPE_DELAY)
497 osl_oshsh_init(osl_t
*osh
, shared_osl_t
* oshsh
)
499 extern unsigned long loops_per_jiffy
;
501 osh
->oshsh
->MIPS
= loops_per_jiffy
/ (500000/HZ
);
505 in_long_delay(osl_t
*osh
)
507 return osh
->oshsh
->long_delay
;
511 osl_long_delay(osl_t
*osh
, uint usec
, bool yield
)
515 int usec_to_delay
= usec
;
516 unsigned long tick1
, tick2
, tick_diff
= 0;
518 /* delay at least requested usec */
519 while (usec_to_delay
> 0) {
520 if (!yield
|| !yielded
) {
521 d
= MIN(usec_to_delay
, 10);
525 if (usec_to_delay
> 0) {
526 osh
->oshsh
->long_delay
++;
527 OSL_GETCYCLES(tick1
);
528 spin_unlock_bh(osh
->oshsh
->lock
);
529 if (usec_to_delay
> 0 && !in_irq() && !in_softirq() && !in_interrupt()) {
535 spin_lock_bh(osh
->oshsh
->lock
);
536 OSL_GETCYCLES(tick2
);
539 tick_diff
= TICKDIFF(tick2
, tick1
);
540 tick_diff
= (tick_diff
* 2)/(osh
->oshsh
->MIPS
);
542 usec_to_delay
-= tick_diff
;
546 osh
->oshsh
->long_delay
--;
547 ASSERT(osh
->oshsh
->long_delay
>= 0);
551 #endif /* DSLCPE_DELAY */
554 * The pkttag contents are NOT cloned.
557 osl_pktdup(osl_t
*osh
, void *skb
)
561 if ((p
= skb_clone((struct sk_buff
*)skb
, GFP_ATOMIC
)) == NULL
)
564 /* skb_clone copies skb->cb.. we don't want that */
566 bzero((void*)((struct sk_buff
*)p
)->cb
, OSL_PKTTAG_SZ
);
568 /* Increment the packet counter */
569 osh
->pub
.pktalloced
++;
571 pktlist_add(&(osh
->pktlist
), (void *) p
);
572 #endif /* BCMDBG_PKT */
577 osl_pktalloced(osl_t
*osh
)
579 return (osh
->pub
.pktalloced
);
584 osl_pktlist_dump(osl_t
*osh
, char *buf
)
586 pktlist_dump(&(osh
->pktlist
), buf
);
591 osl_pktlist_add(osl_t
*osh
, void *p
)
593 pktlist_add(&(osh
->pktlist
), p
);
597 osl_pktlist_remove(osl_t
*osh
, void *p
)
599 pktlist_remove(&(osh
->pktlist
), p
);
601 #endif /* BCMDBG_PKT */
604 * BINOSL selects the slightly slower function-call-based binary compatible osl.
609 osl_printf(const char *format
, ...)
615 /* sprintf into a local buffer because there *is* no "vprintk()".. */
616 va_start(args
, format
);
617 len
= vsnprintf(buf
, 1024, format
, args
);
620 if (len
> sizeof(buf
)) {
621 printk("osl_printf: buffer overrun\n");
625 return (printk(buf
));
629 osl_sprintf(char *buf
, const char *format
, ...)
634 va_start(args
, format
);
635 rc
= vsprintf(buf
, format
, args
);
641 osl_strcmp(const char *s1
, const char *s2
)
643 return (strcmp(s1
, s2
));
647 osl_strncmp(const char *s1
, const char *s2
, uint n
)
649 return (strncmp(s1
, s2
, n
));
653 osl_strlen(const char *s
)
659 osl_strcpy(char *d
, const char *s
)
661 return (strcpy(d
, s
));
665 osl_strncpy(char *d
, const char *s
, uint n
)
667 return (strncpy(d
, s
, n
));
671 bcopy(const void *src
, void *dst
, int len
)
673 memcpy(dst
, src
, len
);
677 bcmp(const void *b1
, const void *b2
, int len
)
679 return (memcmp(b1
, b2
, len
));
683 bzero(void *b
, int len
)
685 memset(b
, '\0', len
);
689 osl_readl(volatile uint32
*r
)
695 osl_readw(volatile uint16
*r
)
701 osl_readb(volatile uint8
*r
)
707 osl_writel(uint32 v
, volatile uint32
*r
)
713 osl_writew(uint16 v
, volatile uint16
*r
)
719 osl_writeb(uint8 v
, volatile uint8
*r
)
725 osl_uncached(void *va
)
728 return ((void*)KSEG1ADDR(va
));
740 cycles
= read_c0_count() * 2;
741 #elif defined(__i386__)
745 #endif /* defined(mips) */
750 osl_reg_map(uint32 pa
, uint size
)
752 return (ioremap_nocache((unsigned long)pa
, (unsigned long)size
));
756 osl_reg_unmap(void *va
)
762 osl_busprobe(uint32
*val
, uint32 addr
)
765 return get_dbe(*val
, (uint32
*)addr
);
767 *val
= readl((uint32
*)(uintptr
)addr
);
773 osl_pktshared(void *skb
)
775 return (((struct sk_buff
*)skb
)->cloned
);
779 osl_pktdata(osl_t
*osh
, void *skb
)
781 return (((struct sk_buff
*)skb
)->data
);
785 osl_pktlen(osl_t
*osh
, void *skb
)
787 return (((struct sk_buff
*)skb
)->len
);
791 osl_pktheadroom(osl_t
*osh
, void *skb
)
793 return (uint
) skb_headroom((struct sk_buff
*) skb
);
797 osl_pkttailroom(osl_t
*osh
, void *skb
)
799 return (uint
) skb_tailroom((struct sk_buff
*) skb
);
803 osl_pktnext(osl_t
*osh
, void *skb
)
805 return (((struct sk_buff
*)skb
)->next
);
809 osl_pktsetnext(void *skb
, void *x
)
811 ((struct sk_buff
*)skb
)->next
= (struct sk_buff
*)x
;
815 osl_pktsetlen(osl_t
*osh
, void *skb
, uint len
)
817 __skb_trim((struct sk_buff
*)skb
, len
);
821 osl_pktpush(osl_t
*osh
, void *skb
, int bytes
)
823 return (skb_push((struct sk_buff
*)skb
, bytes
));
827 osl_pktpull(osl_t
*osh
, void *skb
, int bytes
)
829 return (skb_pull((struct sk_buff
*)skb
, bytes
));
833 osl_pkttag(void *skb
)
835 return ((void*)(((struct sk_buff
*)skb
)->cb
));
839 osl_pktlink(void *skb
)
841 return (((struct sk_buff
*)skb
)->prev
);
845 osl_pktsetlink(void *skb
, void *x
)
847 ((struct sk_buff
*)skb
)->prev
= (struct sk_buff
*)x
;
851 osl_pktprio(void *skb
)
853 return (((struct sk_buff
*)skb
)->priority
);
857 osl_pktsetprio(void *skb
, uint x
)
859 ((struct sk_buff
*)skb
)->priority
= x
;
862 /* Convert a driver packet to native(OS) packet
863 * In the process, packettag is zeroed out before sending up
864 * IP code depends on skb->cb to be setup correctly with various options
865 * In our case, that means it should be 0
868 osl_pkt_tonative(osl_t
*osh
, void *pkt
)
870 struct sk_buff
*nskb
;
873 bzero((void*)((struct sk_buff
*)pkt
)->cb
, OSL_PKTTAG_SZ
);
875 /* Decrement the packet counter */
876 for (nskb
= (struct sk_buff
*)pkt
; nskb
; nskb
= nskb
->next
) {
878 pktlist_remove(&(osh
->pktlist
), (void *) nskb
);
879 #endif /* BCMDBG_PKT */
880 osh
->pub
.pktalloced
--;
883 return (struct sk_buff
*)pkt
;
886 /* Convert a native(OS) packet to driver packet.
887 * In the process, native packet is destroyed, there is no copying
888 * Also, a packettag is zeroed out
891 osl_pkt_frmnative(osl_t
*osh
, struct sk_buff
*skb
)
893 struct sk_buff
*nskb
;
896 bzero((void*)skb
->cb
, OSL_PKTTAG_SZ
);
898 /* Increment the packet counter */
899 for (nskb
= skb
; nskb
; nskb
= nskb
->next
) {
901 pktlist_add(&(osh
->pktlist
), (void *) nskb
);
902 #endif /* BCMDBG_PKT */
903 osh
->pub
.pktalloced
++;