c7628965c0e5cf93ddcd702e654d0a4b33917f36
[deliverable/linux.git] / drivers / staging / brcm80211 / util / linux_osl.c
1 /*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
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.
7 *
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.
15 */
16
17 #include <typedefs.h>
18 #include <bcmendian.h>
19 #include <linuxver.h>
20 #include <bcmdefs.h>
21 #include <osl.h>
22 #include <bcmutils.h>
23 #include <linux/delay.h>
24 #ifdef mips
25 #include <asm/paccess.h>
26 #endif /* mips */
27 #include <pcicfg.h>
28
29 #include <linux/fs.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 struct osl_info {
45 osl_pubinfo_t pub;
46 uint magic;
47 void *pdev;
48 uint malloced;
49 uint failed;
50 uint bustype;
51 bcm_mem_link_t *dbgmem_list;
52 };
53
54 /* Global ASSERT type flag */
55 uint32 g_assert_type;
56
57 static int16 linuxbcmerrormap[] = { 0, /* 0 */
58 -EINVAL, /* BCME_ERROR */
59 -EINVAL, /* BCME_BADARG */
60 -EINVAL, /* BCME_BADOPTION */
61 -EINVAL, /* BCME_NOTUP */
62 -EINVAL, /* BCME_NOTDOWN */
63 -EINVAL, /* BCME_NOTAP */
64 -EINVAL, /* BCME_NOTSTA */
65 -EINVAL, /* BCME_BADKEYIDX */
66 -EINVAL, /* BCME_RADIOOFF */
67 -EINVAL, /* BCME_NOTBANDLOCKED */
68 -EINVAL, /* BCME_NOCLK */
69 -EINVAL, /* BCME_BADRATESET */
70 -EINVAL, /* BCME_BADBAND */
71 -E2BIG, /* BCME_BUFTOOSHORT */
72 -E2BIG, /* BCME_BUFTOOLONG */
73 -EBUSY, /* BCME_BUSY */
74 -EINVAL, /* BCME_NOTASSOCIATED */
75 -EINVAL, /* BCME_BADSSIDLEN */
76 -EINVAL, /* BCME_OUTOFRANGECHAN */
77 -EINVAL, /* BCME_BADCHAN */
78 -EFAULT, /* BCME_BADADDR */
79 -ENOMEM, /* BCME_NORESOURCE */
80 -EOPNOTSUPP, /* BCME_UNSUPPORTED */
81 -EMSGSIZE, /* BCME_BADLENGTH */
82 -EINVAL, /* BCME_NOTREADY */
83 -EPERM, /* BCME_NOTPERMITTED */
84 -ENOMEM, /* BCME_NOMEM */
85 -EINVAL, /* BCME_ASSOCIATED */
86 -ERANGE, /* BCME_RANGE */
87 -EINVAL, /* BCME_NOTFOUND */
88 -EINVAL, /* BCME_WME_NOT_ENABLED */
89 -EINVAL, /* BCME_TSPEC_NOTFOUND */
90 -EINVAL, /* BCME_ACM_NOTSUPPORTED */
91 -EINVAL, /* BCME_NOT_WME_ASSOCIATION */
92 -EIO, /* BCME_SDIO_ERROR */
93 -ENODEV, /* BCME_DONGLE_DOWN */
94 -EINVAL, /* BCME_VERSION */
95 -EIO, /* BCME_TXFAIL */
96 -EIO, /* BCME_RXFAIL */
97 -EINVAL, /* BCME_NODEVICE */
98 -EINVAL, /* BCME_NMODE_DISABLED */
99 -ENODATA, /* BCME_NONRESIDENT */
100
101 /* When an new error code is added to bcmutils.h, add os
102 * spcecific error translation here as well
103 */
104 /* check if BCME_LAST changed since the last time this function was updated */
105 #if BCME_LAST != -42
106 #error "You need to add a OS error translation in the linuxbcmerrormap \
107 for new error code defined in bcmutils.h"
108 #endif
109 };
110
111 /* translate bcmerrors into linux errors */
112 int osl_error(int bcmerror)
113 {
114 if (bcmerror > 0)
115 bcmerror = 0;
116 else if (bcmerror < BCME_LAST)
117 bcmerror = BCME_ERROR;
118
119 /* Array bounds covered by ASSERT in osl_attach */
120 return linuxbcmerrormap[-bcmerror];
121 }
122
123 osl_t *osl_attach(void *pdev, uint bustype, bool pkttag)
124 {
125 osl_t *osh;
126
127 osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
128 ASSERT(osh);
129
130 bzero(osh, sizeof(osl_t));
131
132 /* Check that error map has the right number of entries in it */
133 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
134
135 osh->magic = OS_HANDLE_MAGIC;
136 osh->malloced = 0;
137 osh->failed = 0;
138 osh->dbgmem_list = NULL;
139 osh->pdev = pdev;
140 osh->pub.pkttag = pkttag;
141 osh->bustype = bustype;
142
143 switch (bustype) {
144 case PCI_BUS:
145 case SI_BUS:
146 osh->pub.mmbus = TRUE;
147 break;
148 case JTAG_BUS:
149 case SDIO_BUS:
150 case USB_BUS:
151 case SPI_BUS:
152 case RPC_BUS:
153 osh->pub.mmbus = FALSE;
154 break;
155 default:
156 ASSERT(FALSE);
157 break;
158 }
159
160 #ifdef BCMDBG
161 if (pkttag) {
162 struct sk_buff *skb;
163 ASSERT(OSL_PKTTAG_SZ <= sizeof(skb->cb));
164 }
165 #endif
166 return osh;
167 }
168
169 void osl_detach(osl_t *osh)
170 {
171 if (osh == NULL)
172 return;
173
174 ASSERT(osh->magic == OS_HANDLE_MAGIC);
175 kfree(osh);
176 }
177
178 /* Return a new packet. zero out pkttag */
179 void *BCMFASTPATH osl_pktget(osl_t *osh, uint len)
180 {
181 struct sk_buff *skb;
182
183 skb = dev_alloc_skb(len);
184 if (skb) {
185 skb_put(skb, len);
186 skb->priority = 0;
187
188 osh->pub.pktalloced++;
189 }
190
191 return (void *)skb;
192 }
193
194 /* Free the driver packet. Free the tag if present */
195 void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send)
196 {
197 struct sk_buff *skb, *nskb;
198 int nest = 0;
199
200 skb = (struct sk_buff *)p;
201 ASSERT(skb);
202
203 if (send && osh->pub.tx_fn)
204 osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
205
206 /* perversion: we use skb->next to chain multi-skb packets */
207 while (skb) {
208 nskb = skb->next;
209 skb->next = NULL;
210
211 if (skb->destructor)
212 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
213 * destructor exists
214 */
215 dev_kfree_skb_any(skb);
216 else
217 /* can free immediately (even in_irq()) if destructor
218 * does not exist
219 */
220 dev_kfree_skb(skb);
221
222 osh->pub.pktalloced--;
223 nest++;
224 skb = nskb;
225 }
226 }
227
228 uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size)
229 {
230 uint val = 0;
231 uint retry = PCI_CFG_RETRY;
232
233 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
234
235 /* only 4byte access supported */
236 ASSERT(size == 4);
237
238 do {
239 pci_read_config_dword(osh->pdev, offset, &val);
240 if (val != 0xffffffff)
241 break;
242 } while (retry--);
243
244 #ifdef BCMDBG
245 if (retry < PCI_CFG_RETRY)
246 printk("PCI CONFIG READ access to %d required %d retries\n",
247 offset, (PCI_CFG_RETRY - retry));
248 #endif /* BCMDBG */
249
250 return val;
251 }
252
253 void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
254 {
255 uint retry = PCI_CFG_RETRY;
256
257 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
258
259 /* only 4byte access supported */
260 ASSERT(size == 4);
261
262 do {
263 pci_write_config_dword(osh->pdev, offset, val);
264 if (offset != PCI_BAR0_WIN)
265 break;
266 if (osl_pci_read_config(osh, offset, size) == val)
267 break;
268 } while (retry--);
269
270 #ifdef BCMDBG
271 if (retry < PCI_CFG_RETRY)
272 printk("PCI CONFIG WRITE access to %d required %d retries\n",
273 offset, (PCI_CFG_RETRY - retry));
274 #endif /* BCMDBG */
275 }
276
277 /* return bus # for the pci device pointed by osh->pdev */
278 uint osl_pci_bus(osl_t *osh)
279 {
280 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
281
282 return ((struct pci_dev *)osh->pdev)->bus->number;
283 }
284
285 /* return slot # for the pci device pointed by osh->pdev */
286 uint osl_pci_slot(osl_t *osh)
287 {
288 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
289
290 return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
291 }
292
293 static void
294 osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
295 {
296 }
297
298 void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size)
299 {
300 osl_pcmcia_attr(osh, offset, (char *)buf, size, FALSE);
301 }
302
303 void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size)
304 {
305 osl_pcmcia_attr(osh, offset, (char *)buf, size, TRUE);
306 }
307
308 void *osl_malloc(osl_t *osh, uint size)
309 {
310 void *addr;
311
312 /* only ASSERT if osh is defined */
313 if (osh)
314 ASSERT(osh->magic == OS_HANDLE_MAGIC);
315
316 addr = kmalloc(size, GFP_ATOMIC);
317 if (addr == NULL) {
318 if (osh)
319 osh->failed++;
320 return NULL;
321 }
322 if (osh)
323 osh->malloced += size;
324
325 return addr;
326 }
327
328 void osl_mfree(osl_t *osh, void *addr, uint size)
329 {
330 if (osh) {
331 ASSERT(osh->magic == OS_HANDLE_MAGIC);
332 osh->malloced -= size;
333 }
334 kfree(addr);
335 }
336
337 uint osl_malloced(osl_t *osh)
338 {
339 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
340 return osh->malloced;
341 }
342
343 uint osl_malloc_failed(osl_t *osh)
344 {
345 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
346 return osh->failed;
347 }
348
349 uint osl_dma_consistent_align(void)
350 {
351 return PAGE_SIZE;
352 }
353
354 void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits,
355 uint *alloced, unsigned long *pap)
356 {
357 uint16 align = (1 << align_bits);
358 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
359
360 if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align))
361 size += align;
362 *alloced = size;
363
364 return pci_alloc_consistent(osh->pdev, size, (dma_addr_t *) pap);
365 }
366
367 void osl_dma_free_consistent(osl_t *osh, void *va, uint size, unsigned long pa)
368 {
369 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
370
371 pci_free_consistent(osh->pdev, size, va, (dma_addr_t) pa);
372 }
373
374 uint BCMFASTPATH osl_dma_map(osl_t *osh, void *va, uint size, int direction)
375 {
376 int dir;
377
378 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
379 dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
380 return pci_map_single(osh->pdev, va, size, dir);
381 }
382
383 void BCMFASTPATH osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
384 {
385 int dir;
386
387 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
388 dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
389 pci_unmap_single(osh->pdev, (uint32) pa, size, dir);
390 }
391
392 #if defined(BCMDBG_ASSERT)
393 void osl_assert(char *exp, char *file, int line)
394 {
395 char tempbuf[256];
396 char *basename;
397
398 basename = strrchr(file, '/');
399 /* skip the '/' */
400 if (basename)
401 basename++;
402
403 if (!basename)
404 basename = file;
405
406 #ifdef BCMDBG_ASSERT
407 snprintf(tempbuf, 256,
408 "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
409 basename, line);
410
411 /* Print assert message and give it time to be written to /var/log/messages */
412 if (!in_interrupt()) {
413 const int delay = 3;
414 printk("%s", tempbuf);
415 printk("panic in %d seconds\n", delay);
416 set_current_state(TASK_INTERRUPTIBLE);
417 schedule_timeout(delay * HZ);
418 }
419
420 switch (g_assert_type) {
421 case 0:
422 panic("%s", tempbuf);
423 break;
424 case 1:
425 printk("%s", tempbuf);
426 BUG();
427 break;
428 case 2:
429 printk("%s", tempbuf);
430 break;
431 default:
432 break;
433 }
434 #endif /* BCMDBG_ASSERT */
435
436 }
437 #endif /* defined(BCMDBG_ASSERT) */
438
439 void osl_delay(uint usec)
440 {
441 uint d;
442
443 while (usec > 0) {
444 d = MIN(usec, 1000);
445 udelay(d);
446 usec -= d;
447 }
448 }
449
450 /* Clone a packet.
451 * The pkttag contents are NOT cloned.
452 */
453 void *osl_pktdup(osl_t *osh, void *skb)
454 {
455 void *p;
456
457 p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC);
458 if (p == NULL)
459 return NULL;
460
461 /* skb_clone copies skb->cb.. we don't want that */
462 if (osh->pub.pkttag)
463 bzero((void *)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
464
465 /* Increment the packet counter */
466 osh->pub.pktalloced++;
467 return p;
468 }
469
470 #ifdef BCMSDIO
471 u8 osl_readb(osl_t *osh, volatile u8 *r)
472 {
473 osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn;
474 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
475
476 return (u8) ((rreg) (ctx, (void *)r, sizeof(u8)));
477 }
478
479 uint16 osl_readw(osl_t *osh, volatile uint16 *r)
480 {
481 osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn;
482 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
483
484 return (uint16) ((rreg) (ctx, (void *)r, sizeof(uint16)));
485 }
486
487 uint32 osl_readl(osl_t *osh, volatile uint32 *r)
488 {
489 osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn;
490 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
491
492 return (uint32) ((rreg) (ctx, (void *)r, sizeof(uint32)));
493 }
494
495 void osl_writeb(osl_t *osh, volatile u8 *r, u8 v)
496 {
497 osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn;
498 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
499
500 ((wreg) (ctx, (void *)r, v, sizeof(u8)));
501 }
502
503 void osl_writew(osl_t *osh, volatile uint16 *r, uint16 v)
504 {
505 osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn;
506 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
507
508 ((wreg) (ctx, (void *)r, v, sizeof(uint16)));
509 }
510
511 void osl_writel(osl_t *osh, volatile uint32 *r, uint32 v)
512 {
513 osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn;
514 void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
515
516 ((wreg) (ctx, (void *)r, v, sizeof(uint32)));
517 }
518 #endif /* BCMSDIO */
519 /* Linux Kernel: File Operations: end */
This page took 0.052546 seconds and 4 git commands to generate.