[MINI2440] Updated defconfig to add (optional) packages
[openwrt/mini2440.git] / package / broadcom-wl / src / driver / linux_osl.c
blobcc55eb68e9d37321a44c5ab8d77077c7ffb666b1
1 /*
2 * Linux OS Independent Layer
4 * Copyright 2007, Broadcom Corporation
5 * All Rights Reserved.
6 *
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.
12 * $Id$
15 #define LINUX_OSL
17 #include <typedefs.h>
18 #include <bcmendian.h>
19 #include <linuxver.h>
20 #include <bcmdefs.h>
21 #include <osl.h>
22 #include "linux_osl.h"
23 #include "bcmutils.h"
24 #include <linux/delay.h>
25 #ifdef mips
26 #include <asm/paccess.h>
27 #endif /* mips */
28 #include <pcicfg.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;
39 uint size;
40 int line;
41 char file[BCM_MEM_FILENAME_LEN];
42 } bcm_mem_link_t;
44 #if 0
45 struct osl_info
47 osl_pubinfo_t pub;
48 uint magic;
49 void *pdev;
50 uint malloced;
51 uint failed;
52 uint bustype;
53 bcm_mem_link_t *dbgmem_list;
54 #ifdef BCMDBG_PKT /* pkt logging for debugging */
55 pktlist_info_t pktlist;
56 #endif /* BCMDBG_PKT */
58 #endif
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 */
102 #if BCME_LAST != -37
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)
112 if (bcmerror > 0)
113 bcmerror = 0;
114 else if (bcmerror < BCME_LAST)
115 bcmerror = BCME_ERROR;
117 /* Array bounds covered by ASSERT in osl_attach */
118 return linuxbcmerrormap[-bcmerror];
121 osl_t *
122 osl_attach (void *pdev, uint bustype, bool pkttag)
124 osl_t *osh;
126 osh = kmalloc (sizeof (osl_t), GFP_ATOMIC);
127 ASSERT (osh);
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;
135 osh->malloced = 0;
136 osh->failed = 0;
137 osh->dbgmem_list = NULL;
138 osh->pdev = pdev;
139 osh->pub.pkttag = pkttag;
140 osh->bustype = bustype;
142 switch (bustype)
144 case PCI_BUS:
145 case SB_BUS:
146 case PCMCIA_BUS:
147 osh->pub.mmbus = TRUE;
148 break;
149 case JTAG_BUS:
150 case SDIO_BUS:
151 break;
152 default:
153 ASSERT (FALSE);
154 break;
157 #ifdef BCMDBG
158 if (pkttag)
160 struct sk_buff *skb;
161 ASSERT (OSL_PKTTAG_SZ <= sizeof (skb->cb));
163 #endif
164 return osh;
167 void
168 osl_detach (osl_t * osh)
170 if (osh == NULL)
171 return;
173 ASSERT (osh->magic == OS_HANDLE_MAGIC);
174 kfree (osh);
177 /* Return a new packet. zero out pkttag */
178 void *
179 osl_pktget (osl_t * osh, uint len)
181 struct sk_buff *skb;
183 if ((skb = dev_alloc_skb (len)))
185 skb_put (skb, len);
186 skb->priority = 0;
188 #ifdef BCMDBG_PKT
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 */
199 void
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 */
210 while (skb)
212 nskb = skb->next;
213 skb->next = NULL;
215 #ifdef BCMDBG_PKT
216 pktlist_remove (&(osh->pktlist), (void *) skb);
217 #endif /* BCMDBG_PKT */
219 if (skb->destructor)
221 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists
223 dev_kfree_skb_any (skb);
225 else
227 /* can free immediately (even in_irq()) if destructor does not exist */
228 dev_kfree_skb (skb);
231 osh->pub.pktalloced--;
233 skb = nskb;
237 uint32
238 osl_pci_read_config (osl_t * osh, uint offset, uint size)
240 uint val;
241 uint retry = PCI_CFG_RETRY;
243 ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
245 /* only 4byte access supported */
246 ASSERT (size == 4);
250 pci_read_config_dword (osh->pdev, offset, &val);
251 if (val != 0xffffffff)
252 break;
254 while (retry--);
256 #ifdef BCMDBG
257 if (retry < PCI_CFG_RETRY)
258 printk ("PCI CONFIG READ access to %d required %d retries\n", offset,
259 (PCI_CFG_RETRY - retry));
260 #endif /* BCMDBG */
262 return (val);
265 void
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 */
273 ASSERT (size == 4);
277 pci_write_config_dword (osh->pdev, offset, val);
278 if (offset != PCI_BAR0_WIN)
279 break;
280 if (osl_pci_read_config (osh, offset, size) == val)
281 break;
283 while (retry--);
285 #ifdef BCMDBG
286 if (retry < PCI_CFG_RETRY)
287 printk ("PCI CONFIG WRITE access to %d required %d retries\n", offset,
288 (PCI_CFG_RETRY - retry));
289 #endif /* BCMDBG */
292 /* return bus # for the pci device pointed by osh->pdev */
293 uint
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 */
302 uint
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);
310 static void
311 osl_pcmcia_attr (osl_t * osh, uint offset, char *buf, int size, bool write)
315 void
316 osl_pcmcia_read_attr (osl_t * osh, uint offset, void *buf, int size)
318 osl_pcmcia_attr (osh, offset, (char *) buf, size, FALSE);
321 void
322 osl_pcmcia_write_attr (osl_t * osh, uint offset, void *buf, int size)
324 osl_pcmcia_attr (osh, offset, (char *) buf, size, TRUE);
328 #ifdef BCMDBG_MEM
330 void *
331 osl_debug_malloc (osl_t * osh, uint size, int line, char *file)
333 bcm_mem_link_t *p;
334 char *basename;
336 ASSERT (size);
338 if ((p =
339 (bcm_mem_link_t *) osl_malloc (osh,
340 sizeof (bcm_mem_link_t) + size)) ==
341 NULL)
342 return (NULL);
344 p->size = size;
345 p->line = line;
347 basename = strrchr (file, '/');
348 /* skip the '/' */
349 if (basename)
350 basename++;
352 if (!basename)
353 basename = file;
355 strncpy (p->file, basename, BCM_MEM_FILENAME_LEN);
356 p->file[BCM_MEM_FILENAME_LEN - 1] = '\0';
358 /* link this block */
359 p->prev = NULL;
360 p->next = osh->dbgmem_list;
361 if (p->next)
362 p->next->prev = p;
363 osh->dbgmem_list = p;
365 return p + 1;
368 void
369 osl_debug_mfree (osl_t * osh, void *addr, uint size, int line, char *file)
371 bcm_mem_link_t *p =
372 (bcm_mem_link_t *) ((int8 *) addr - sizeof (bcm_mem_link_t));
374 ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
376 if (p->size == 0)
378 printk
379 ("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n",
380 addr, size, line, file);
381 ASSERT (p->size);
382 return;
385 if (p->size != size)
387 printk
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);
391 return;
394 /* unlink this block */
395 if (p->prev)
396 p->prev->next = p->next;
397 if (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)
409 bcm_mem_link_t *p;
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,
417 p->line);
419 return 0;
422 #endif /* BCMDBG_MEM */
424 void *
425 osl_malloc (osl_t * osh, uint size)
427 void *addr;
429 /* only ASSERT if osh is defined */
430 if (osh)
431 ASSERT (osh->magic == OS_HANDLE_MAGIC);
433 if ((addr = kmalloc (size, GFP_ATOMIC)) == NULL)
435 if (osh)
436 osh->failed++;
437 return (NULL);
439 if (osh)
440 osh->malloced += size;
442 return (addr);
445 void
446 osl_mfree (osl_t * osh, void *addr, uint size)
448 if (osh)
450 ASSERT (osh->magic == OS_HANDLE_MAGIC);
451 osh->malloced -= size;
453 kfree (addr);
456 uint
457 osl_malloced (osl_t * osh)
459 ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
460 return (osh->malloced);
463 uint
464 osl_malloc_failed (osl_t * osh)
466 ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
467 return (osh->failed);
470 void *
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));
478 void
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);
486 uint
487 osl_dma_map (osl_t * osh, void *va, uint size, int direction)
489 int dir;
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));
496 void
497 osl_dma_unmap (osl_t * osh, uint pa, uint size, int direction)
499 int dir;
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)
507 void
508 osl_assert (char *exp, char *file, int line)
510 char tempbuf[255];
512 sprintf (tempbuf, "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
513 file, line);
514 panic (tempbuf);
516 #endif /* BCMDBG_ASSERT || BINOSL */
518 void
519 osl_delay (uint usec)
521 uint d;
523 while (usec > 0)
525 d = MIN (usec, 1000);
526 udelay (d);
527 usec -= d;
531 /* Clone a packet.
532 * The pkttag contents are NOT cloned.
534 void *
535 osl_pktdup (osl_t * osh, void *skb)
537 void *p;
539 if ((p = skb_clone ((struct sk_buff *) skb, GFP_ATOMIC)) == NULL)
540 return NULL;
542 /* skb_clone copies skb->cb.. we don't want that */
543 if (osh->pub.pkttag)
544 bzero ((void *) ((struct sk_buff *) p)->cb, OSL_PKTTAG_SZ);
546 /* Increment the packet counter */
547 osh->pub.pktalloced++;
548 #ifdef BCMDBG_PKT
549 pktlist_add (&(osh->pktlist), (void *) p);
550 #endif /* BCMDBG_PKT */
551 return (p);
554 uint
555 osl_pktalloced (osl_t * osh)
557 return (osh->pub.pktalloced);
560 #ifdef BCMDBG_PKT
561 char *
562 osl_pktlist_dump (osl_t * osh, char *buf)
564 pktlist_dump (&(osh->pktlist), buf);
565 return buf;
568 void
569 osl_pktlist_add (osl_t * osh, void *p)
571 pktlist_add (&(osh->pktlist), p);
574 void
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.
584 #ifdef BINOSL
587 osl_printf (const char *format, ...)
589 va_list args;
590 char buf[1024];
591 int len;
593 /* sprintf into a local buffer because there *is* no "vprintk()".. */
594 va_start (args, format);
595 len = vsnprintf (buf, 1024, format, args);
596 va_end (args);
598 if (len > sizeof (buf))
600 printk ("osl_printf: buffer overrun\n");
601 return (0);
604 return (printk (buf));
608 osl_sprintf (char *buf, const char *format, ...)
610 va_list args;
611 int rc;
613 va_start (args, format);
614 rc = vsprintf (buf, format, args);
615 va_end (args);
616 return (rc);
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)
634 return (strlen (s));
637 char *
638 osl_strcpy (char *d, const char *s)
640 return (strcpy (d, s));
643 char *
644 osl_strncpy (char *d, const char *s, uint n)
646 return (strncpy (d, s, n));
649 void
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));
661 void
662 bzero (void *b, int len)
664 memset (b, '\0', len);
667 uint32
668 osl_readl (volatile uint32 * r)
670 return (readl (r));
673 uint16
674 osl_readw (volatile uint16 * r)
676 return (readw (r));
679 uint8
680 osl_readb (volatile uint8 * r)
682 return (readb (r));
685 void
686 osl_writel (uint32 v, volatile uint32 * r)
688 writel (v, r);
691 void
692 osl_writew (uint16 v, volatile uint16 * r)
694 writew (v, r);
697 void
698 osl_writeb (uint8 v, volatile uint8 * r)
700 writeb (v, r);
703 void *
704 osl_uncached (void *va)
706 #ifdef mips
707 return ((void *) KSEG1ADDR (va));
708 #else
709 return ((void *) va);
710 #endif /* mips */
713 uint
714 osl_getcycles (void)
716 uint cycles;
718 #if defined(mips)
719 cycles = read_c0_count () * 2;
720 #elif defined(__i386__)
721 rdtscl (cycles);
722 #else
723 cycles = 0;
724 #endif /* defined(mips) */
725 return cycles;
728 void *
729 osl_reg_map (uint32 pa, uint size)
731 return (ioremap_nocache ((unsigned long) pa, (unsigned long) size));
734 void
735 osl_reg_unmap (void *va)
737 iounmap (va);
741 osl_busprobe (uint32 * val, uint32 addr)
743 #ifdef mips
744 return get_dbe (*val, (uint32 *) addr);
745 #else
746 *val = readl ((uint32 *) (uintptr) addr);
747 return 0;
748 #endif /* mips */
751 bool
752 osl_pktshared (void *skb)
754 return (((struct sk_buff *) skb)->cloned);
757 uchar *
758 osl_pktdata (osl_t * osh, void *skb)
760 return (((struct sk_buff *) skb)->data);
763 uint
764 osl_pktlen (osl_t * osh, void *skb)
766 return (((struct sk_buff *) skb)->len);
769 uint
770 osl_pktheadroom (osl_t * osh, void *skb)
772 return (uint) skb_headroom ((struct sk_buff *) skb);
775 uint
776 osl_pkttailroom (osl_t * osh, void *skb)
778 return (uint) skb_tailroom ((struct sk_buff *) skb);
781 void *
782 osl_pktnext (osl_t * osh, void *skb)
784 return (((struct sk_buff *) skb)->next);
787 void
788 osl_pktsetnext (void *skb, void *x)
790 ((struct sk_buff *) skb)->next = (struct sk_buff *) x;
793 void
794 osl_pktsetlen (osl_t * osh, void *skb, uint len)
796 __skb_trim ((struct sk_buff *) skb, len);
799 uchar *
800 osl_pktpush (osl_t * osh, void *skb, int bytes)
802 return (skb_push ((struct sk_buff *) skb, bytes));
805 uchar *
806 osl_pktpull (osl_t * osh, void *skb, int bytes)
808 return (skb_pull ((struct sk_buff *) skb, bytes));
811 void *
812 osl_pkttag (void *skb)
814 return ((void *) (((struct sk_buff *) skb)->cb));
817 void *
818 osl_pktlink (void *skb)
820 return (((struct sk_buff *) skb)->prev);
823 void
824 osl_pktsetlink (void *skb, void *x)
826 ((struct sk_buff *) skb)->prev = (struct sk_buff *) x;
829 uint
830 osl_pktprio (void *skb)
832 return (((struct sk_buff *) skb)->priority);
835 void
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
846 struct sk_buff *
847 osl_pkt_tonative (osl_t * osh, void *pkt)
849 struct sk_buff *nskb;
851 if (osh->pub.pkttag)
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)
857 #ifdef BCMDBG_PKT
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
870 void *
871 osl_pkt_frmnative (osl_t * osh, struct sk_buff *skb)
873 struct sk_buff *nskb;
875 if (osh->pub.pkttag)
876 bzero ((void *) skb->cb, OSL_PKTTAG_SZ);
878 /* Increment the packet counter */
879 for (nskb = skb; nskb; nskb = nskb->next)
881 #ifdef BCMDBG_PKT
882 pktlist_add (&(osh->pktlist), (void *) nskb);
883 #endif /* BCMDBG_PKT */
884 osh->pub.pktalloced++;
887 return (void *) skb;
890 #endif /* BINOSL */