upgrade to broadcom wl driver version 4.80.53.0 (from wrt350n release)
[openwrt.git] / package / broadcom-wl / src / kmod / linux_osl.c
1 /*
2  * Linux OS Independent Layer
3  *
4  * Copyright 2006, 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.
11  *
12  * $Id: linux_osl.c,v 1.1.1.14 2006/04/08 06:13:39 honor Exp $
13  */
14
15 #define LINUX_OSL
16
17 #include <typedefs.h>
18 #include <bcmendian.h>
19 #include <linux/module.h>
20 #include <linuxver.h>
21 #include <bcmdefs.h>
22 #include <osl.h>
23 #include "linux_osl.h"
24 #include <bcmutils.h>
25 #include <linux/delay.h>
26 #ifdef mips
27 #include <asm/paccess.h>
28 #endif /* mips */
29 #include <pcicfg.h>
30
31 #define PCI_CFG_RETRY           10      
32
33 #define OS_HANDLE_MAGIC         0x1234abcd      /* Magic # to recognise osh */
34 #define BCM_MEM_FILENAME_LEN    24              /* Mem. filename length */
35
36 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;
43
44 static int16 linuxbcmerrormap[] =  \
45 {       0,                      /* 0 */
46         -EINVAL,                /* BCME_ERROR */
47         -EINVAL,                /* BCME_BADARG */
48         -EINVAL,                /* BCME_BADOPTION */
49         -EINVAL,                /* BCME_NOTUP */
50         -EINVAL,                /* BCME_NOTDOWN */
51         -EINVAL,                /* BCME_NOTAP */
52         -EINVAL,                /* BCME_NOTSTA */
53         -EINVAL,                /* BCME_BADKEYIDX */
54         -EINVAL,                /* BCME_RADIOOFF */
55         -EINVAL,                /* BCME_NOTBANDLOCKED */
56         -EINVAL,                /* BCME_NOCLK */
57         -EINVAL,                /* BCME_BADRATESET */
58         -EINVAL,                /* BCME_BADBAND */
59         -E2BIG,                 /* BCME_BUFTOOSHORT */
60         -E2BIG,                 /* BCME_BUFTOOLONG */
61         -EBUSY,                 /* BCME_BUSY */
62         -EINVAL,                /* BCME_NOTASSOCIATED */
63         -EINVAL,                /* BCME_BADSSIDLEN */
64         -EINVAL,                /* BCME_OUTOFRANGECHAN */
65         -EINVAL,                /* BCME_BADCHAN */
66         -EFAULT,                /* BCME_BADADDR */
67         -ENOMEM,                /* BCME_NORESOURCE */
68         -EOPNOTSUPP,            /* BCME_UNSUPPORTED */
69         -EMSGSIZE,              /* BCME_BADLENGTH */
70         -EINVAL,                /* BCME_NOTREADY */
71         -EPERM,                 /* BCME_NOTPERMITTED */
72         -ENOMEM,                /* BCME_NOMEM */
73         -EINVAL,                /* BCME_ASSOCIATED */
74         -ERANGE,                /* BCME_RANGE */
75         -EINVAL,                /* BCME_NOTFOUND */
76         -EINVAL,                /* BCME_WME_NOT_ENABLED */
77         -EINVAL,                /* BCME_TSPEC_NOTFOUND */
78         -EINVAL,                /* BCME_ACM_NOTSUPPORTED */
79         -EINVAL,                /* BCME_NOT_WME_ASSOCIATION */
80         -EIO,                   /* BCME_SDIO_ERROR */
81         -ENODEV                 /* BCME_DONGLE_DOWN */
82 };
83
84 /* translate bcmerrors into linux errors */
85 int
86 osl_error(int bcmerror)
87 {
88         int abs_bcmerror;
89         int array_size = ARRAYSIZE(linuxbcmerrormap);
90
91         abs_bcmerror = ABS(bcmerror);
92
93         if (bcmerror > 0)
94                 abs_bcmerror = 0;
95
96         else if (abs_bcmerror >= array_size)
97                 abs_bcmerror = BCME_ERROR;
98
99         return linuxbcmerrormap[abs_bcmerror];
100 }
101
102 osl_t *
103 osl_attach(void *pdev, bool pkttag)
104 {
105         osl_t *osh;
106
107         osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
108         ASSERT(osh);
109
110         bzero(osh, sizeof(osl_t));
111
112         /*
113          * check the cases where
114          * 1.Error code Added to bcmerror table, but forgot to add it to the OS
115          * dependent error code
116          * 2. Error code is added to the bcmerror table, but forgot to add the
117          * corresponding errorstring(dummy call to bcmerrorstr)
118          */
119         bcmerrorstr(0);
120         ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
121
122         osh->magic = OS_HANDLE_MAGIC;
123         osh->malloced = 0;
124         osh->failed = 0;
125         osh->dbgmem_list = NULL;
126         osh->pdev = pdev;
127         osh->pub.pkttag = pkttag;
128
129         return osh;
130 }
131
132 void
133 osl_detach(osl_t *osh)
134 {
135         if (osh == NULL)
136                 return;
137
138         ASSERT(osh->magic == OS_HANDLE_MAGIC);
139         kfree(osh);
140 }
141
142 /* Return a new packet. zero out pkttag */
143 void*
144 osl_pktget(osl_t *osh, uint len, bool send)
145 {
146         struct sk_buff *skb;
147
148         if ((skb = dev_alloc_skb(len))) {
149                 skb_put(skb, len);
150                 skb->priority = 0;
151
152 #ifdef BCMDBG_PKT
153         pktlist_add(&(osh->pktlist), (void *) skb);
154 #endif  /* BCMDBG_PKT */
155
156                 osh->pub.pktalloced++;
157         }
158
159         return ((void*) skb);
160 }
161
162 typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, uint16 status);
163 /* Free the driver packet. Free the tag if present */
164 void
165 osl_pktfree(osl_t *osh, void *p, bool send)
166 {
167         struct sk_buff *skb, *nskb;
168         pktfree_cb_fn_t tx_fn = osh->pub.tx_fn;
169
170         skb = (struct sk_buff*) p;
171         
172         if (send && tx_fn)
173                 tx_fn(osh->pub.tx_ctx, p, 0);
174
175         /* perversion: we use skb->next to chain multi-skb packets */
176         while (skb) {
177                 nskb = skb->next;
178                 skb->next = NULL;
179
180 #ifdef BCMDBG_PKT
181                 pktlist_remove(&(osh->pktlist), (void *) skb);
182 #endif  /* BCMDBG_PKT */
183
184                 if (skb->destructor) {
185                         /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists
186                          */
187                         dev_kfree_skb_any(skb);
188                 } else {
189                         /* can free immediately (even in_irq()) if destructor does not exist */
190                         dev_kfree_skb(skb);
191                 }
192
193                 osh->pub.pktalloced--;
194
195                 skb = nskb;
196         }
197 }
198
199 void*
200 osl_malloc(osl_t *osh, uint size)
201 {
202         void *addr;
203
204         /* only ASSERT if osh is defined */
205         if (osh)
206                 ASSERT(osh->magic == OS_HANDLE_MAGIC);
207
208         if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) {
209                 if (osh)
210                         osh->failed++;
211                 return (NULL);
212         }
213         if (osh)
214                 osh->malloced += size;
215
216         return (addr);
217 }
218
219 void
220 osl_mfree(osl_t *osh, void *addr, uint size)
221 {
222         if (osh) {
223                 ASSERT(osh->magic == OS_HANDLE_MAGIC);
224                 osh->malloced -= size;
225         }
226         kfree(addr);
227 }
228
229 uint
230 osl_malloced(osl_t *osh)
231 {
232         ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
233         return (osh->malloced);
234 }
235
236 uint osl_malloc_failed(osl_t *osh)
237 {
238         ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
239         return (osh->failed);
240 }
241
242 #undef osl_delay
243 void
244 osl_delay(uint usec)
245 {
246         OSL_DELAY(usec);
247 }
248
249 /* Clone a packet.
250  * The pkttag contents are NOT cloned.
251  */
252 void *
253 osl_pktdup(osl_t *osh, void *skb)
254 {
255         void * p;
256
257         if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL)
258                 return NULL;
259
260         /* skb_clone copies skb->cb.. we don't want that */
261         if (osh->pub.pkttag)
262                 bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
263
264         /* Increment the packet counter */
265         osh->pub.pktalloced++;
266         return (p);
267 }
268
269 uint
270 osl_pktalloced(osl_t *osh)
271 {
272         return (osh->pub.pktalloced);
273 }
274