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