Home | History | Annotate | Download | only in shared
      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
    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 *
    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
    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*
    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
    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*
    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
    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
    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
    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
    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
    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
    436 osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
    437 {
    438 }
    439 
    440 void
    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
    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*
    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
    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
    541 osl_malloced(osl_t *osh)
    542 {
    543 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
    544 	return (osh->malloced);
    545 }
    546 
    547 uint
    548 osl_malloc_failed(osl_t *osh)
    549 {
    550 	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
    551 	return (osh->failed);
    552 }
    553 
    554 void*
    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
    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
    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
    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
    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 *
    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