• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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