1 /*
2 * Linux OS Independent Layer
3 *
4 * Copyright (C) 1999-2009, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: linux_osl.c,v 1.125.12.3.8.5 2009/10/27 04:43:04 Exp $
25 */
26
27
28 #define LINUX_OSL
29
30 #include <typedefs.h>
31 #include <bcmendian.h>
32 #include <linuxver.h>
33 #include <bcmdefs.h>
34 #include <osl.h>
35 #include <bcmutils.h>
36 #include <linux/delay.h>
37 #include <pcicfg.h>
38
39 #define PCI_CFG_RETRY 10
40
41 #define OS_HANDLE_MAGIC 0x1234abcd
42 #define BCM_MEM_FILENAME_LEN 24
43
44 #ifdef DHD_USE_STATIC_BUF
45 #define MAX_STATIC_BUF_NUM 16
46 #define STATIC_BUF_SIZE (PAGE_SIZE*2)
47 #define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE)
48 typedef struct bcm_static_buf {
49 struct semaphore static_sem;
50 unsigned char *buf_ptr;
51 unsigned char buf_use[MAX_STATIC_BUF_NUM];
52 } bcm_static_buf_t;
53
54 static bcm_static_buf_t *bcm_static_buf = 0;
55
56 #define MAX_STATIC_PKT_NUM 8
57 typedef struct bcm_static_pkt {
58 struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM];
59 struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM];
60 struct semaphore osl_pkt_sem;
61 unsigned char pkt_use[MAX_STATIC_PKT_NUM*2];
62 } bcm_static_pkt_t;
63 static bcm_static_pkt_t *bcm_static_skb = 0;
64
65 #endif
66 typedef struct bcm_mem_link {
67 struct bcm_mem_link *prev;
68 struct bcm_mem_link *next;
69 uint size;
70 int line;
71 char file[BCM_MEM_FILENAME_LEN];
72 } bcm_mem_link_t;
73
74 struct osl_info {
75 osl_pubinfo_t pub;
76 uint magic;
77 void *pdev;
78 uint malloced;
79 uint failed;
80 uint bustype;
81 bcm_mem_link_t *dbgmem_list;
82 };
83
84 static int16 linuxbcmerrormap[] = \
85 { 0,
86 -EINVAL,
87 -EINVAL,
88 -EINVAL,
89 -EINVAL,
90 -EINVAL,
91 -EINVAL,
92 -EINVAL,
93 -EINVAL,
94 -EINVAL,
95 -EINVAL,
96 -EINVAL,
97 -EINVAL,
98 -EINVAL,
99 -E2BIG,
100 -E2BIG,
101 -EBUSY,
102 -EINVAL,
103 -EINVAL,
104 -EINVAL,
105 -EINVAL,
106 -EFAULT,
107 -ENOMEM,
108 -EOPNOTSUPP,
109 -EMSGSIZE,
110 -EINVAL,
111 -EPERM,
112 -ENOMEM,
113 -EINVAL,
114 -ERANGE,
115 -EINVAL,
116 -EINVAL,
117 -EINVAL,
118 -EINVAL,
119 -EINVAL,
120 -EIO,
121 -ENODEV,
122 -EINVAL,
123 -EINVAL
124
125
126
127 #if BCME_LAST != -38
128 #error "You need to add a OS error translation in the linuxbcmerrormap \
129 for new error code defined in bcmuitls.h"
130 #endif
131 };
132
133
134 int
osl_error(int bcmerror)135 osl_error(int bcmerror)
136 {
137 if (bcmerror > 0)
138 bcmerror = 0;
139 else if (bcmerror < BCME_LAST)
140 bcmerror = BCME_ERROR;
141
142
143 return linuxbcmerrormap[-bcmerror];
144 }
145
146 void * dhd_os_prealloc(int section, unsigned long size);
147 osl_t *
osl_attach(void * pdev,uint bustype,bool pkttag)148 osl_attach(void *pdev, uint bustype, bool pkttag)
149 {
150 osl_t *osh;
151 gfp_t flags;
152
153 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
154 osh = kmalloc(sizeof(osl_t), flags);
155 ASSERT(osh);
156
157 bzero(osh, sizeof(osl_t));
158
159
160 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
161
162 osh->magic = OS_HANDLE_MAGIC;
163 osh->malloced = 0;
164 osh->failed = 0;
165 osh->dbgmem_list = NULL;
166 osh->pdev = pdev;
167 osh->pub.pkttag = pkttag;
168 osh->bustype = bustype;
169
170 switch (bustype) {
171 case PCI_BUS:
172 case SI_BUS:
173 case PCMCIA_BUS:
174 osh->pub.mmbus = TRUE;
175 break;
176 case JTAG_BUS:
177 case SDIO_BUS:
178 case USB_BUS:
179 case SPI_BUS:
180 osh->pub.mmbus = FALSE;
181 break;
182 default:
183 ASSERT(FALSE);
184 break;
185 }
186
187 #ifdef DHD_USE_STATIC_BUF
188
189
190 if (!bcm_static_buf) {
191 if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(3, STATIC_BUF_SIZE+
192 STATIC_BUF_TOTAL_LEN))) {
193 printk("can not alloc static buf!\n");
194 }
195 else {
196 /* printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); */
197 }
198
199 init_MUTEX(&bcm_static_buf->static_sem);
200
201
202 bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
203
204 }
205
206 if (!bcm_static_skb)
207 {
208 int i;
209 void *skb_buff_ptr = 0;
210 bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
211 skb_buff_ptr = dhd_os_prealloc(4, 0);
212
213 bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16);
214 for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++)
215 bcm_static_skb->pkt_use[i] = 0;
216
217 init_MUTEX(&bcm_static_skb->osl_pkt_sem);
218 }
219 #endif
220 return osh;
221 }
222
223 void
osl_detach(osl_t * osh)224 osl_detach(osl_t *osh)
225 {
226 if (osh == NULL)
227 return;
228
229 #ifdef DHD_USE_STATIC_BUF
230 if (bcm_static_buf) {
231 bcm_static_buf = 0;
232 }
233 if (bcm_static_skb) {
234 bcm_static_skb = 0;
235 }
236 #endif
237 ASSERT(osh->magic == OS_HANDLE_MAGIC);
238 kfree(osh);
239 }
240
241
242 void*
osl_pktget(osl_t * osh,uint len)243 osl_pktget(osl_t *osh, uint len)
244 {
245 struct sk_buff *skb;
246
247 if ((skb = dev_alloc_skb(len))) {
248 skb_put(skb, len);
249 skb->priority = 0;
250
251
252 osh->pub.pktalloced++;
253 }
254
255 return ((void*) skb);
256 }
257
258
259 void
osl_pktfree(osl_t * osh,void * p,bool send)260 osl_pktfree(osl_t *osh, void *p, bool send)
261 {
262 struct sk_buff *skb, *nskb;
263
264 skb = (struct sk_buff*) p;
265
266 if (send && osh->pub.tx_fn)
267 osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
268
269
270 while (skb) {
271 nskb = skb->next;
272 skb->next = NULL;
273
274
275 if (skb->destructor) {
276
277 dev_kfree_skb_any(skb);
278 } else {
279
280 dev_kfree_skb(skb);
281 }
282
283 osh->pub.pktalloced--;
284
285 skb = nskb;
286 }
287 }
288
289 #ifdef DHD_USE_STATIC_BUF
290 void*
osl_pktget_static(osl_t * osh,uint len)291 osl_pktget_static(osl_t *osh, uint len)
292 {
293 int i = 0;
294 struct sk_buff *skb;
295
296
297 if (len > (PAGE_SIZE*2))
298 {
299 printk("Do we really need this big skb??\n");
300 return osl_pktget(osh, len);
301 }
302
303
304 down(&bcm_static_skb->osl_pkt_sem);
305 if (len <= PAGE_SIZE)
306 {
307
308 for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
309 {
310 if (bcm_static_skb->pkt_use[i] == 0)
311 break;
312 }
313
314 if (i != MAX_STATIC_PKT_NUM)
315 {
316 bcm_static_skb->pkt_use[i] = 1;
317 up(&bcm_static_skb->osl_pkt_sem);
318
319 skb = bcm_static_skb->skb_4k[i];
320 skb->tail = skb->data + len;
321 skb->len = len;
322
323 return skb;
324 }
325 }
326
327
328 for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
329 {
330 if (bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] == 0)
331 break;
332 }
333
334 if (i != MAX_STATIC_PKT_NUM)
335 {
336 bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] = 1;
337 up(&bcm_static_skb->osl_pkt_sem);
338 skb = bcm_static_skb->skb_8k[i];
339 skb->tail = skb->data + len;
340 skb->len = len;
341
342 return skb;
343 }
344
345
346
347 up(&bcm_static_skb->osl_pkt_sem);
348 printk("all static pkt in use!\n");
349 return osl_pktget(osh, len);
350 }
351
352
353 void
osl_pktfree_static(osl_t * osh,void * p,bool send)354 osl_pktfree_static(osl_t *osh, void *p, bool send)
355 {
356 int i;
357
358 for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++)
359 {
360 if (p == bcm_static_skb->skb_4k[i])
361 {
362 down(&bcm_static_skb->osl_pkt_sem);
363 bcm_static_skb->pkt_use[i] = 0;
364 up(&bcm_static_skb->osl_pkt_sem);
365
366
367 return;
368 }
369 }
370 return osl_pktfree(osh, p, send);
371 }
372 #endif
373 uint32
osl_pci_read_config(osl_t * osh,uint offset,uint size)374 osl_pci_read_config(osl_t *osh, uint offset, uint size)
375 {
376 uint val = 0;
377 uint retry = PCI_CFG_RETRY;
378
379 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
380
381
382 ASSERT(size == 4);
383
384 do {
385 pci_read_config_dword(osh->pdev, offset, &val);
386 if (val != 0xffffffff)
387 break;
388 } while (retry--);
389
390
391 return (val);
392 }
393
394 void
osl_pci_write_config(osl_t * osh,uint offset,uint size,uint val)395 osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
396 {
397 uint retry = PCI_CFG_RETRY;
398
399 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
400
401
402 ASSERT(size == 4);
403
404 do {
405 pci_write_config_dword(osh->pdev, offset, val);
406 if (offset != PCI_BAR0_WIN)
407 break;
408 if (osl_pci_read_config(osh, offset, size) == val)
409 break;
410 } while (retry--);
411
412 }
413
414
415 uint
osl_pci_bus(osl_t * osh)416 osl_pci_bus(osl_t *osh)
417 {
418 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
419
420 return ((struct pci_dev *)osh->pdev)->bus->number;
421 }
422
423
424 uint
osl_pci_slot(osl_t * osh)425 osl_pci_slot(osl_t *osh)
426 {
427 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
428
429 return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
430 }
431
432 static void
osl_pcmcia_attr(osl_t * osh,uint offset,char * buf,int size,bool write)433 osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
434 {
435 }
436
437 void
osl_pcmcia_read_attr(osl_t * osh,uint offset,void * buf,int size)438 osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size)
439 {
440 osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE);
441 }
442
443 void
osl_pcmcia_write_attr(osl_t * osh,uint offset,void * buf,int size)444 osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size)
445 {
446 osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE);
447 }
448
449
450
451 void*
osl_malloc(osl_t * osh,uint size)452 osl_malloc(osl_t *osh, uint size)
453 {
454 void *addr;
455 gfp_t flags;
456
457 if (osh)
458 ASSERT(osh->magic == OS_HANDLE_MAGIC);
459
460 #ifdef DHD_USE_STATIC_BUF
461 if (bcm_static_buf)
462 {
463 int i = 0;
464 if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE))
465 {
466 down(&bcm_static_buf->static_sem);
467
468 for (i = 0; i < MAX_STATIC_BUF_NUM; i++)
469 {
470 if (bcm_static_buf->buf_use[i] == 0)
471 break;
472 }
473
474 if (i == MAX_STATIC_BUF_NUM)
475 {
476 up(&bcm_static_buf->static_sem);
477 printk("all static buff in use!\n");
478 goto original;
479 }
480
481 bcm_static_buf->buf_use[i] = 1;
482 up(&bcm_static_buf->static_sem);
483
484 bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size);
485 if (osh)
486 osh->malloced += size;
487
488 return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i));
489 }
490 }
491 original:
492 #endif
493 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
494 if ((addr = kmalloc(size, flags)) == NULL) {
495 if (osh)
496 osh->failed++;
497 return (NULL);
498 }
499 if (osh)
500 osh->malloced += size;
501
502 return (addr);
503 }
504
505 void
osl_mfree(osl_t * osh,void * addr,uint size)506 osl_mfree(osl_t *osh, void *addr, uint size)
507 {
508 #ifdef DHD_USE_STATIC_BUF
509 if (bcm_static_buf)
510 {
511 if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr \
512 <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN)))
513 {
514 int buf_idx = 0;
515
516 buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE;
517
518 down(&bcm_static_buf->static_sem);
519 bcm_static_buf->buf_use[buf_idx] = 0;
520 up(&bcm_static_buf->static_sem);
521
522 if (osh) {
523 ASSERT(osh->magic == OS_HANDLE_MAGIC);
524 osh->malloced -= size;
525 }
526 return;
527 }
528 }
529 #endif
530 if (osh) {
531 ASSERT(osh->magic == OS_HANDLE_MAGIC);
532 osh->malloced -= size;
533 }
534 kfree(addr);
535 }
536
537 uint
osl_malloced(osl_t * osh)538 osl_malloced(osl_t *osh)
539 {
540 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
541 return (osh->malloced);
542 }
543
544 uint
osl_malloc_failed(osl_t * osh)545 osl_malloc_failed(osl_t *osh)
546 {
547 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
548 return (osh->failed);
549 }
550
551 void*
osl_dma_alloc_consistent(osl_t * osh,uint size,ulong * pap)552 osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap)
553 {
554 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
555
556 return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap));
557 }
558
559 void
osl_dma_free_consistent(osl_t * osh,void * va,uint size,ulong pa)560 osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa)
561 {
562 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
563
564 pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa);
565 }
566
567 uint
osl_dma_map(osl_t * osh,void * va,uint size,int direction)568 osl_dma_map(osl_t *osh, void *va, uint size, int direction)
569 {
570 int dir;
571
572 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
573 dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
574 return (pci_map_single(osh->pdev, va, size, dir));
575 }
576
577 void
osl_dma_unmap(osl_t * osh,uint pa,uint size,int direction)578 osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
579 {
580 int dir;
581
582 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
583 dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
584 pci_unmap_single(osh->pdev, (uint32)pa, size, dir);
585 }
586
587
588 void
osl_delay(uint usec)589 osl_delay(uint usec)
590 {
591 uint d;
592
593 while (usec > 0) {
594 d = MIN(usec, 1000);
595 udelay(d);
596 usec -= d;
597 }
598 }
599
600
601
602 void *
osl_pktdup(osl_t * osh,void * skb)603 osl_pktdup(osl_t *osh, void *skb)
604 {
605 void * p;
606 gfp_t flags;
607
608 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
609 if ((p = skb_clone((struct sk_buff*)skb, flags)) == NULL)
610 return NULL;
611
612
613 if (osh->pub.pkttag)
614 bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
615
616
617 osh->pub.pktalloced++;
618 return (p);
619 }
620