PageRenderTime 27ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Kernel/drivers/net/wireless/bcm4329/src/shared/linux_osl.c

https://github.com/CoreyUnknown/linux_froyo_gt-i9000
C | 701 lines | 532 code | 144 blank | 25 comment | 110 complexity | 93447b6d7225e1ee2d22e89c2b487726 MD5 | raw file
  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. #define LINUX_OSL
  27. #if defined(CHROMIUMOS_COMPAT_WIRELESS)
  28. #include <linux/sched.h>
  29. #endif
  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. #ifdef DHD_DEBUG
  39. #define OSL_MSG_ERROR(x) printk x
  40. #define OSL_MSG_INFO(x)
  41. #else
  42. #define OSL_MSG_ERROR(x)
  43. #define OSL_MSG_INFO(x)
  44. #endif
  45. #define PCI_CFG_RETRY 10
  46. #define OS_HANDLE_MAGIC 0x1234abcd
  47. #define BCM_MEM_FILENAME_LEN 24
  48. #ifdef DHD_USE_STATIC_BUF
  49. #define DHD_SKB_HDRSIZE 336
  50. #define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE)
  51. #define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE)
  52. #define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE)
  53. #define MAX_STATIC_BUF_NUM 16
  54. #define STATIC_BUF_SIZE (PAGE_SIZE*2)
  55. #define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE)
  56. typedef struct bcm_static_buf {
  57. struct semaphore static_sem;
  58. unsigned char *buf_ptr;
  59. unsigned char buf_use[MAX_STATIC_BUF_NUM];
  60. } bcm_static_buf_t;
  61. static bcm_static_buf_t *bcm_static_buf = 0;
  62. #define MAX_STATIC_PKT_NUM 8
  63. typedef struct bcm_static_pkt {
  64. struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM];
  65. struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM];
  66. struct sk_buff *skb_16k;
  67. struct semaphore osl_pkt_sem;
  68. unsigned char pkt_use[MAX_STATIC_PKT_NUM*2+1];
  69. } bcm_static_pkt_t;
  70. static bcm_static_pkt_t *bcm_static_skb = 0;
  71. #endif
  72. typedef struct bcm_mem_link {
  73. struct bcm_mem_link *prev;
  74. struct bcm_mem_link *next;
  75. uint size;
  76. int line;
  77. char file[BCM_MEM_FILENAME_LEN];
  78. } bcm_mem_link_t;
  79. struct osl_info {
  80. osl_pubinfo_t pub;
  81. uint magic;
  82. void *pdev;
  83. uint malloced;
  84. uint failed;
  85. uint bustype;
  86. bcm_mem_link_t *dbgmem_list;
  87. };
  88. static int16 linuxbcmerrormap[] =
  89. { 0,
  90. -EINVAL,
  91. -EINVAL,
  92. -EINVAL,
  93. -EINVAL,
  94. -EINVAL,
  95. -EINVAL,
  96. -EINVAL,
  97. -EINVAL,
  98. -EINVAL,
  99. -EINVAL,
  100. -EINVAL,
  101. -EINVAL,
  102. -EINVAL,
  103. -E2BIG,
  104. -E2BIG,
  105. -EBUSY,
  106. -EINVAL,
  107. -EINVAL,
  108. -EINVAL,
  109. -EINVAL,
  110. -EFAULT,
  111. -ENOMEM,
  112. -EOPNOTSUPP,
  113. -EMSGSIZE,
  114. -EINVAL,
  115. -EPERM,
  116. -ENOMEM,
  117. -EINVAL,
  118. -ERANGE,
  119. -EINVAL,
  120. -EINVAL,
  121. -EINVAL,
  122. -EINVAL,
  123. -EINVAL,
  124. -EIO,
  125. -ENODEV,
  126. -EINVAL,
  127. -EIO,
  128. -EIO,
  129. -EINVAL,
  130. -EINVAL,
  131. #if BCME_LAST != -41
  132. #error "You need to add a OS error translation in the linuxbcmerrormap \
  133. for new error code defined in bcmutils.h"
  134. #endif
  135. };
  136. int
  137. osl_error(int bcmerror)
  138. {
  139. if (bcmerror > 0)
  140. bcmerror = 0;
  141. else if (bcmerror < BCME_LAST)
  142. bcmerror = BCME_ERROR;
  143. return linuxbcmerrormap[-bcmerror];
  144. }
  145. void * dhd_os_prealloc(int section, unsigned long size);
  146. osl_t *
  147. osl_attach(void *pdev, uint bustype, bool pkttag)
  148. {
  149. osl_t *osh;
  150. osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
  151. ASSERT(osh);
  152. bzero(osh, sizeof(osl_t));
  153. ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
  154. osh->magic = OS_HANDLE_MAGIC;
  155. osh->malloced = 0;
  156. osh->failed = 0;
  157. osh->dbgmem_list = NULL;
  158. osh->pdev = pdev;
  159. osh->pub.pkttag = pkttag;
  160. osh->bustype = bustype;
  161. switch (bustype) {
  162. case PCI_BUS:
  163. case SI_BUS:
  164. case PCMCIA_BUS:
  165. osh->pub.mmbus = TRUE;
  166. break;
  167. case JTAG_BUS:
  168. case SDIO_BUS:
  169. case USB_BUS:
  170. case SPI_BUS:
  171. osh->pub.mmbus = FALSE;
  172. break;
  173. default:
  174. ASSERT(FALSE);
  175. break;
  176. }
  177. #ifdef DHD_USE_STATIC_BUF
  178. if (!bcm_static_buf) {
  179. if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(3, STATIC_BUF_SIZE+
  180. STATIC_BUF_TOTAL_LEN))) {
  181. OSL_MSG_ERROR(("osl_attach: can not alloc static buf!\n"));
  182. }
  183. else
  184. OSL_MSG_INFO(("osl_attach: alloc static buf at %x!\n", (unsigned int)bcm_static_buf));
  185. init_MUTEX(&bcm_static_buf->static_sem);
  186. bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
  187. }
  188. if (!bcm_static_skb)
  189. {
  190. int i;
  191. #ifndef CUSTOMER_HW_SAMSUNG
  192. void *skb_buff_ptr = 0;
  193. #endif
  194. bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
  195. #ifdef CUSTOMER_HW_SAMSUNG
  196. for (i = 0; i < MAX_STATIC_PKT_NUM; i++) {
  197. bcm_static_skb->skb_4k[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE);
  198. if (bcm_static_skb->skb_4k[i] == NULL) {
  199. OSL_MSG_ERROR(("osl_attach: 4K memory allocation failure. idx=%d\n", i));
  200. goto err;
  201. }
  202. }
  203. for (i = 0; i < MAX_STATIC_PKT_NUM; i++) {
  204. bcm_static_skb->skb_8k[i] = dev_alloc_skb_kernel(DHD_SKB_2PAGE_BUFSIZE);
  205. if (bcm_static_skb->skb_8k[i] == NULL) {
  206. OSL_MSG_ERROR(("osl_attach: 8K memory allocation failure. idx=%d\n", i));
  207. goto err;
  208. }
  209. }
  210. bcm_static_skb->skb_16k = dev_alloc_skb_kernel(DHD_SKB_4PAGE_BUFSIZE);
  211. if (bcm_static_skb->skb_16k == NULL) {
  212. OSL_MSG_ERROR(("osl_attach: 16K memory allocation failure. idx=%d\n", i));
  213. goto err;
  214. }
  215. #else
  216. skb_buff_ptr = dhd_os_prealloc(4, 0);
  217. bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16);
  218. #endif /* CUSTOMER_HW_SAMSUNG */
  219. for (i = 0; i < MAX_STATIC_PKT_NUM*2+1; i++)
  220. bcm_static_skb->pkt_use[i] = 0;
  221. init_MUTEX(&bcm_static_skb->osl_pkt_sem);
  222. }
  223. #endif
  224. return osh;
  225. err:
  226. kfree(osh);
  227. return 0;
  228. }
  229. void
  230. osl_detach(osl_t *osh)
  231. {
  232. if (osh == NULL)
  233. return;
  234. #ifdef DHD_USE_STATIC_BUF
  235. if (bcm_static_buf) {
  236. bcm_static_buf = 0;
  237. }
  238. if (bcm_static_skb) {
  239. int i;
  240. down(&bcm_static_skb->osl_pkt_sem);
  241. for(i=0; i<MAX_STATIC_PKT_NUM*2+1; i++) {
  242. dev_kfree_skb(bcm_static_skb->skb_4k[i]);
  243. }
  244. up(&bcm_static_skb->osl_pkt_sem);
  245. bcm_static_skb = 0;
  246. }
  247. #endif
  248. ASSERT(osh->magic == OS_HANDLE_MAGIC);
  249. kfree(osh);
  250. }
  251. void*
  252. osl_pktget(osl_t *osh, uint len)
  253. {
  254. struct sk_buff *skb;
  255. if ((skb = dev_alloc_skb(len))) {
  256. skb_put(skb, len);
  257. skb->priority = 0;
  258. osh->pub.pktalloced++;
  259. }
  260. return ((void*) skb);
  261. }
  262. void*
  263. osl_pktget_kernel(osl_t *osh, uint len)
  264. {
  265. struct sk_buff *skb;
  266. if ((skb = dev_alloc_skb_kernel(len))) {
  267. skb_put(skb, len);
  268. skb->priority = 0;
  269. osh->pub.pktalloced++;
  270. }
  271. return ((void*) skb);
  272. }
  273. void
  274. osl_pktfree(osl_t *osh, void *p, bool send)
  275. {
  276. struct sk_buff *skb, *nskb;
  277. skb = (struct sk_buff*) p;
  278. if (send && osh->pub.tx_fn)
  279. osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
  280. while (skb) {
  281. nskb = skb->next;
  282. skb->next = NULL;
  283. if (skb->destructor) {
  284. dev_kfree_skb_any(skb);
  285. } else {
  286. dev_kfree_skb(skb);
  287. }
  288. osh->pub.pktalloced--;
  289. skb = nskb;
  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. if (len > DHD_SKB_4PAGE_BUFSIZE)
  299. {
  300. OSL_MSG_ERROR(("osl_pktget_static: Do we really need this big skb?? len=%d\n", len));
  301. return osl_pktget_kernel(osh, len);
  302. }
  303. down(&bcm_static_skb->osl_pkt_sem);
  304. if (len <= DHD_SKB_1PAGE_BUFSIZE)
  305. {
  306. for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
  307. {
  308. if (bcm_static_skb->pkt_use[i] == 0)
  309. break;
  310. }
  311. if (i != MAX_STATIC_PKT_NUM)
  312. {
  313. bcm_static_skb->pkt_use[i] = 1;
  314. up(&bcm_static_skb->osl_pkt_sem);
  315. skb = bcm_static_skb->skb_4k[i];
  316. skb->tail = skb->data + len;
  317. skb->len = len;
  318. return skb;
  319. }
  320. }
  321. if (len <= DHD_SKB_2PAGE_BUFSIZE)
  322. {
  323. for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
  324. {
  325. if (bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] == 0)
  326. break;
  327. }
  328. if (i != MAX_STATIC_PKT_NUM)
  329. {
  330. bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] = 1;
  331. up(&bcm_static_skb->osl_pkt_sem);
  332. skb = bcm_static_skb->skb_8k[i];
  333. skb->tail = skb->data + len;
  334. skb->len = len;
  335. return skb;
  336. }
  337. }
  338. if (bcm_static_skb->pkt_use[MAX_STATIC_PKT_NUM*2] == 0)
  339. {
  340. bcm_static_skb->pkt_use[MAX_STATIC_PKT_NUM*2] = 1;
  341. up(&bcm_static_skb->osl_pkt_sem);
  342. skb = bcm_static_skb->skb_16k;
  343. skb->tail = skb->data + len;
  344. skb->len = len;
  345. return skb;
  346. }
  347. up(&bcm_static_skb->osl_pkt_sem);
  348. OSL_MSG_ERROR(("osl_pktget_static: all static pkt in use!\n"));
  349. return osl_pktget(osh, len);
  350. }
  351. void
  352. osl_pktfree_static(osl_t *osh, void *p, bool send)
  353. {
  354. int i;
  355. for (i = 0; i < MAX_STATIC_PKT_NUM*2+1; i++)
  356. {
  357. if (p == bcm_static_skb->skb_4k[i])
  358. {
  359. down(&bcm_static_skb->osl_pkt_sem);
  360. bcm_static_skb->pkt_use[i] = 0;
  361. up(&bcm_static_skb->osl_pkt_sem);
  362. return;
  363. }
  364. }
  365. return osl_pktfree(osh, p, send);
  366. }
  367. #endif
  368. uint32
  369. osl_pci_read_config(osl_t *osh, uint offset, uint size)
  370. {
  371. uint val = 0;
  372. uint retry = PCI_CFG_RETRY;
  373. ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
  374. ASSERT(size == 4);
  375. do {
  376. pci_read_config_dword(osh->pdev, offset, &val);
  377. if (val != 0xffffffff)
  378. break;
  379. } while (retry--);
  380. return (val);
  381. }
  382. void
  383. osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
  384. {
  385. uint retry = PCI_CFG_RETRY;
  386. ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
  387. ASSERT(size == 4);
  388. do {
  389. pci_write_config_dword(osh->pdev, offset, val);
  390. if (offset != PCI_BAR0_WIN)
  391. break;
  392. if (osl_pci_read_config(osh, offset, size) == val)
  393. break;
  394. } while (retry--);
  395. }
  396. uint
  397. osl_pci_bus(osl_t *osh)
  398. {
  399. ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
  400. return ((struct pci_dev *)osh->pdev)->bus->number;
  401. }
  402. uint
  403. osl_pci_slot(osl_t *osh)
  404. {
  405. ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
  406. return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
  407. }
  408. static void
  409. osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
  410. {
  411. }
  412. void
  413. osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size)
  414. {
  415. osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE);
  416. }
  417. void
  418. osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size)
  419. {
  420. osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE);
  421. }
  422. void*
  423. osl_malloc(osl_t *osh, uint size)
  424. {
  425. void *addr;
  426. if (osh)
  427. ASSERT(osh->magic == OS_HANDLE_MAGIC);
  428. #ifdef DHD_USE_STATIC_BUF
  429. if (bcm_static_buf)
  430. {
  431. int i = 0;
  432. if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE))
  433. {
  434. down(&bcm_static_buf->static_sem);
  435. for (i = 0; i < MAX_STATIC_BUF_NUM; i++)
  436. {
  437. if (bcm_static_buf->buf_use[i] == 0)
  438. break;
  439. }
  440. if (i == MAX_STATIC_BUF_NUM)
  441. {
  442. up(&bcm_static_buf->static_sem);
  443. OSL_MSG_INFO(("osl_malloc: all static buff in use!\n"));
  444. goto original;
  445. }
  446. bcm_static_buf->buf_use[i] = 1;
  447. up(&bcm_static_buf->static_sem);
  448. bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size);
  449. if (osh)
  450. osh->malloced += size;
  451. return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i));
  452. }
  453. }
  454. original:
  455. #endif
  456. if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) {
  457. OSL_MSG_ERROR(("osl_malloc: GFP_ATOMIC failed, trying GFP_KERNEL\n"));
  458. if ((addr = kmalloc(size, GFP_KERNEL)) == NULL) {
  459. OSL_MSG_ERROR(("osl_malloc: GFP_KERNEL failed also\n"));
  460. if (osh)
  461. osh->failed++;
  462. return (NULL);
  463. }
  464. }
  465. if (osh)
  466. osh->malloced += size;
  467. return (addr);
  468. }
  469. void
  470. osl_mfree(osl_t *osh, void *addr, uint size)
  471. {
  472. #ifdef DHD_USE_STATIC_BUF
  473. if (bcm_static_buf)
  474. {
  475. if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr
  476. <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN)))
  477. {
  478. int buf_idx = 0;
  479. buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE;
  480. down(&bcm_static_buf->static_sem);
  481. bcm_static_buf->buf_use[buf_idx] = 0;
  482. up(&bcm_static_buf->static_sem);
  483. if (osh) {
  484. ASSERT(osh->magic == OS_HANDLE_MAGIC);
  485. osh->malloced -= size;
  486. }
  487. return;
  488. }
  489. }
  490. #endif
  491. if (osh) {
  492. ASSERT(osh->magic == OS_HANDLE_MAGIC);
  493. osh->malloced -= size;
  494. }
  495. kfree(addr);
  496. }
  497. uint
  498. osl_malloced(osl_t *osh)
  499. {
  500. ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
  501. return (osh->malloced);
  502. }
  503. uint
  504. osl_malloc_failed(osl_t *osh)
  505. {
  506. ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
  507. return (osh->failed);
  508. }
  509. void*
  510. osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap)
  511. {
  512. ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
  513. return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap));
  514. }
  515. void
  516. osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa)
  517. {
  518. ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
  519. pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa);
  520. }
  521. uint
  522. osl_dma_map(osl_t *osh, void *va, uint size, int direction)
  523. {
  524. int dir;
  525. ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
  526. dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
  527. return (pci_map_single(osh->pdev, va, size, dir));
  528. }
  529. void
  530. osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
  531. {
  532. int dir;
  533. ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
  534. dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
  535. pci_unmap_single(osh->pdev, (uint32)pa, size, dir);
  536. }
  537. void
  538. osl_delay(uint usec)
  539. {
  540. uint d;
  541. while (usec > 0) {
  542. d = MIN(usec, 1000);
  543. udelay(d);
  544. usec -= d;
  545. }
  546. }
  547. void *
  548. osl_pktdup(osl_t *osh, void *skb)
  549. {
  550. void * p;
  551. if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL)
  552. return NULL;
  553. if (osh->pub.pkttag)
  554. bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
  555. osh->pub.pktalloced++;
  556. return (p);
  557. }