• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Linux OS Independent Layer
3  *
4  * Copyright (C) 1999-2010, 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.7 2010/05/04 21:10: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 	-EIO,
124 	-EIO,
125 	-EINVAL,
126 	-EINVAL,
127 
128 
129 
130 #if BCME_LAST != -41
131 #error "You need to add a OS error translation in the linuxbcmerrormap \
132 	for new error code defined in bcmutils.h"
133 #endif
134 };
135 
136 
137 int
osl_error(int bcmerror)138 osl_error(int bcmerror)
139 {
140 	if (bcmerror > 0)
141 		bcmerror = 0;
142 	else if (bcmerror < BCME_LAST)
143 		bcmerror = BCME_ERROR;
144 
145 
146 	return linuxbcmerrormap[-bcmerror];
147 }
148 
149 void * dhd_os_prealloc(int section, unsigned long size);
150 osl_t *
osl_attach(void * pdev,uint bustype,bool pkttag)151 osl_attach(void *pdev, uint bustype, bool pkttag)
152 {
153 	osl_t *osh;
154 	gfp_t flags;
155 
156 	flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
157 	osh = kmalloc(sizeof(osl_t), flags);
158 	ASSERT(osh);
159 
160 	bzero(osh, sizeof(osl_t));
161 
162 
163 	ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
164 
165 	osh->magic = OS_HANDLE_MAGIC;
166 	osh->malloced = 0;
167 	osh->failed = 0;
168 	osh->dbgmem_list = NULL;
169 	osh->pdev = pdev;
170 	osh->pub.pkttag = pkttag;
171 	osh->bustype = bustype;
172 
173 	switch (bustype) {
174 		case PCI_BUS:
175 		case SI_BUS:
176 		case PCMCIA_BUS:
177 			osh->pub.mmbus = TRUE;
178 			break;
179 		case JTAG_BUS:
180 		case SDIO_BUS:
181 		case USB_BUS:
182 		case SPI_BUS:
183 			osh->pub.mmbus = FALSE;
184 			break;
185 		default:
186 			ASSERT(FALSE);
187 			break;
188 	}
189 
190 #ifdef DHD_USE_STATIC_BUF
191 
192 
193 	if (!bcm_static_buf) {
194 		if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(3, STATIC_BUF_SIZE+
195 			STATIC_BUF_TOTAL_LEN))) {
196 			printk("can not alloc static buf!\n");
197 		}
198 		else {
199 			/* printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); */
200 		}
201 
202 		init_MUTEX(&bcm_static_buf->static_sem);
203 
204 
205 		bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
206 
207 	}
208 
209 	if (!bcm_static_skb)
210 	{
211 		int i;
212 		void *skb_buff_ptr = 0;
213 		bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
214 		skb_buff_ptr = dhd_os_prealloc(4, 0);
215 
216 		bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16);
217 		for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++)
218 			bcm_static_skb->pkt_use[i] = 0;
219 
220 		init_MUTEX(&bcm_static_skb->osl_pkt_sem);
221 	}
222 #endif
223 	return osh;
224 }
225 
226 void
osl_detach(osl_t * osh)227 osl_detach(osl_t *osh)
228 {
229 	if (osh == NULL)
230 		return;
231 
232 #ifdef DHD_USE_STATIC_BUF
233 	if (bcm_static_buf) {
234 		bcm_static_buf = 0;
235 	}
236 	if (bcm_static_skb) {
237 		bcm_static_skb = 0;
238 	}
239 #endif
240 	ASSERT(osh->magic == OS_HANDLE_MAGIC);
241 	kfree(osh);
242 }
243 
244 
245 void*
osl_pktget(osl_t * osh,uint len)246 osl_pktget(osl_t *osh, uint len)
247 {
248 	struct sk_buff *skb;
249 
250 	if ((skb = dev_alloc_skb(len))) {
251 		skb_put(skb, len);
252 		skb->priority = 0;
253 
254 
255 		osh->pub.pktalloced++;
256 	}
257 
258 	return ((void*) skb);
259 }
260 
261 
262 void
osl_pktfree(osl_t * osh,void * p,bool send)263 osl_pktfree(osl_t *osh, void *p, bool send)
264 {
265 	struct sk_buff *skb, *nskb;
266 
267 	skb = (struct sk_buff*) p;
268 
269 	if (send && osh->pub.tx_fn)
270 		osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
271 
272 
273 	while (skb) {
274 		nskb = skb->next;
275 		skb->next = NULL;
276 
277 
278 		if (skb->destructor) {
279 
280 			dev_kfree_skb_any(skb);
281 		} else {
282 
283 			dev_kfree_skb(skb);
284 		}
285 
286 		osh->pub.pktalloced--;
287 
288 		skb = nskb;
289 	}
290 }
291 
292 #ifdef DHD_USE_STATIC_BUF
293 void*
osl_pktget_static(osl_t * osh,uint len)294 osl_pktget_static(osl_t *osh, uint len)
295 {
296 	int i = 0;
297 	struct sk_buff *skb;
298 
299 
300 	if (len > (PAGE_SIZE*2))
301 	{
302 		printk("Do we really need this big skb??\n");
303 		return osl_pktget(osh, len);
304 	}
305 
306 
307 	down(&bcm_static_skb->osl_pkt_sem);
308 	if (len <= PAGE_SIZE)
309 	{
310 
311 		for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
312 		{
313 			if (bcm_static_skb->pkt_use[i] == 0)
314 				break;
315 		}
316 
317 		if (i != MAX_STATIC_PKT_NUM)
318 		{
319 			bcm_static_skb->pkt_use[i] = 1;
320 			up(&bcm_static_skb->osl_pkt_sem);
321 
322 			skb = bcm_static_skb->skb_4k[i];
323 			skb->tail = skb->data + len;
324 			skb->len = len;
325 
326 			return skb;
327 		}
328 	}
329 
330 
331 	for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
332 	{
333 		if (bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] == 0)
334 			break;
335 	}
336 
337 	if (i != MAX_STATIC_PKT_NUM)
338 	{
339 		bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] = 1;
340 		up(&bcm_static_skb->osl_pkt_sem);
341 		skb = bcm_static_skb->skb_8k[i];
342 		skb->tail = skb->data + len;
343 		skb->len = len;
344 
345 		return skb;
346 	}
347 
348 
349 
350 	up(&bcm_static_skb->osl_pkt_sem);
351 	printk("all static pkt in use!\n");
352 	return osl_pktget(osh, len);
353 }
354 
355 
356 void
osl_pktfree_static(osl_t * osh,void * p,bool send)357 osl_pktfree_static(osl_t *osh, void *p, bool send)
358 {
359 	int i;
360 
361 	for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++)
362 	{
363 		if (p == bcm_static_skb->skb_4k[i])
364 		{
365 			down(&bcm_static_skb->osl_pkt_sem);
366 			bcm_static_skb->pkt_use[i] = 0;
367 			up(&bcm_static_skb->osl_pkt_sem);
368 
369 
370 			return;
371 		}
372 	}
373 	return osl_pktfree(osh, p, send);
374 }
375 #endif
376 uint32
osl_pci_read_config(osl_t * osh,uint offset,uint size)377 osl_pci_read_config(osl_t *osh, uint offset, uint size)
378 {
379 	uint val = 0;
380 	uint retry = PCI_CFG_RETRY;
381 
382 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
383 
384 
385 	ASSERT(size == 4);
386 
387 	do {
388 		pci_read_config_dword(osh->pdev, offset, &val);
389 		if (val != 0xffffffff)
390 			break;
391 	} while (retry--);
392 
393 
394 	return (val);
395 }
396 
397 void
osl_pci_write_config(osl_t * osh,uint offset,uint size,uint val)398 osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
399 {
400 	uint retry = PCI_CFG_RETRY;
401 
402 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
403 
404 
405 	ASSERT(size == 4);
406 
407 	do {
408 		pci_write_config_dword(osh->pdev, offset, val);
409 		if (offset != PCI_BAR0_WIN)
410 			break;
411 		if (osl_pci_read_config(osh, offset, size) == val)
412 			break;
413 	} while (retry--);
414 
415 }
416 
417 
418 uint
osl_pci_bus(osl_t * osh)419 osl_pci_bus(osl_t *osh)
420 {
421 	ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
422 
423 	return ((struct pci_dev *)osh->pdev)->bus->number;
424 }
425 
426 
427 uint
osl_pci_slot(osl_t * osh)428 osl_pci_slot(osl_t *osh)
429 {
430 	ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
431 
432 	return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
433 }
434 
435 static void
osl_pcmcia_attr(osl_t * osh,uint offset,char * buf,int size,bool write)436 osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
437 {
438 }
439 
440 void
osl_pcmcia_read_attr(osl_t * osh,uint offset,void * buf,int size)441 osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size)
442 {
443 	osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE);
444 }
445 
446 void
osl_pcmcia_write_attr(osl_t * osh,uint offset,void * buf,int size)447 osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size)
448 {
449 	osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE);
450 }
451 
452 
453 
454 void*
osl_malloc(osl_t * osh,uint size)455 osl_malloc(osl_t *osh, uint size)
456 {
457 	void *addr;
458 	gfp_t flags;
459 
460 	if (osh)
461 		ASSERT(osh->magic == OS_HANDLE_MAGIC);
462 
463 #ifdef DHD_USE_STATIC_BUF
464 	if (bcm_static_buf)
465 	{
466 		int i = 0;
467 		if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE))
468 		{
469 			down(&bcm_static_buf->static_sem);
470 
471 			for (i = 0; i < MAX_STATIC_BUF_NUM; i++)
472 			{
473 				if (bcm_static_buf->buf_use[i] == 0)
474 					break;
475 			}
476 
477 			if (i == MAX_STATIC_BUF_NUM)
478 			{
479 				up(&bcm_static_buf->static_sem);
480 				printk("all static buff in use!\n");
481 				goto original;
482 			}
483 
484 			bcm_static_buf->buf_use[i] = 1;
485 			up(&bcm_static_buf->static_sem);
486 
487 			bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size);
488 			if (osh)
489 				osh->malloced += size;
490 
491 			return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i));
492 		}
493 	}
494 original:
495 #endif
496 	flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
497 	if ((addr = kmalloc(size, flags)) == NULL) {
498 		if (osh)
499 			osh->failed++;
500 		return (NULL);
501 	}
502 	if (osh)
503 		osh->malloced += size;
504 
505 	return (addr);
506 }
507 
508 void
osl_mfree(osl_t * osh,void * addr,uint size)509 osl_mfree(osl_t *osh, void *addr, uint size)
510 {
511 #ifdef DHD_USE_STATIC_BUF
512 	if (bcm_static_buf)
513 	{
514 		if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr
515 			<= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN)))
516 		{
517 			int buf_idx = 0;
518 
519 			buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE;
520 
521 			down(&bcm_static_buf->static_sem);
522 			bcm_static_buf->buf_use[buf_idx] = 0;
523 			up(&bcm_static_buf->static_sem);
524 
525 			if (osh) {
526 				ASSERT(osh->magic == OS_HANDLE_MAGIC);
527 				osh->malloced -= size;
528 			}
529 			return;
530 		}
531 	}
532 #endif
533 	if (osh) {
534 		ASSERT(osh->magic == OS_HANDLE_MAGIC);
535 		osh->malloced -= size;
536 	}
537 	kfree(addr);
538 }
539 
540 uint
osl_malloced(osl_t * osh)541 osl_malloced(osl_t *osh)
542 {
543 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
544 	return (osh->malloced);
545 }
546 
547 uint
osl_malloc_failed(osl_t * osh)548 osl_malloc_failed(osl_t *osh)
549 {
550 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
551 	return (osh->failed);
552 }
553 
554 void*
osl_dma_alloc_consistent(osl_t * osh,uint size,ulong * pap)555 osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap)
556 {
557 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
558 
559 	return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap));
560 }
561 
562 void
osl_dma_free_consistent(osl_t * osh,void * va,uint size,ulong pa)563 osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa)
564 {
565 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
566 
567 	pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa);
568 }
569 
570 uint
osl_dma_map(osl_t * osh,void * va,uint size,int direction)571 osl_dma_map(osl_t *osh, void *va, uint size, int direction)
572 {
573 	int dir;
574 
575 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
576 	dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
577 	return (pci_map_single(osh->pdev, va, size, dir));
578 }
579 
580 void
osl_dma_unmap(osl_t * osh,uint pa,uint size,int direction)581 osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
582 {
583 	int dir;
584 
585 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
586 	dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
587 	pci_unmap_single(osh->pdev, (uint32)pa, size, dir);
588 }
589 
590 
591 void
osl_delay(uint usec)592 osl_delay(uint usec)
593 {
594 	uint d;
595 
596 	while (usec > 0) {
597 		d = MIN(usec, 1000);
598 		udelay(d);
599 		usec -= d;
600 	}
601 }
602 
603 
604 
605 void *
osl_pktdup(osl_t * osh,void * skb)606 osl_pktdup(osl_t *osh, void *skb)
607 {
608 	void * p;
609 	gfp_t flags;
610 
611 	flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
612 	if ((p = skb_clone((struct sk_buff*)skb, flags)) == NULL)
613 		return NULL;
614 
615 
616 	if (osh->pub.pkttag)
617 		bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
618 
619 
620 	osh->pub.pktalloced++;
621 	return (p);
622 }
623