PageRenderTime 27ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/net/wireless/bcm4329/linux_osl.c

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