/drivers/staging/crystalhd/crystalhd_misc.c

https://bitbucket.org/wisechild/galaxy-nexus · C · 1032 lines · 623 code · 116 blank · 293 comment · 147 complexity · c6a65cd2c5852e043cd34ad40e267611 MD5 · raw file

  1. /***************************************************************************
  2. * Copyright (c) 2005-2009, Broadcom Corporation.
  3. *
  4. * Name: crystalhd_misc . c
  5. *
  6. * Description:
  7. * BCM70012 Linux driver misc routines.
  8. *
  9. * HISTORY:
  10. *
  11. **********************************************************************
  12. * This file is part of the crystalhd device driver.
  13. *
  14. * This driver is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation, version 2 of the License.
  17. *
  18. * This driver is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this driver. If not, see <http://www.gnu.org/licenses/>.
  25. **********************************************************************/
  26. #include <linux/slab.h>
  27. #include "crystalhd_misc.h"
  28. #include "crystalhd_lnx.h"
  29. uint32_t g_linklog_level;
  30. static inline uint32_t crystalhd_dram_rd(struct crystalhd_adp *adp, uint32_t mem_off)
  31. {
  32. crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19));
  33. return bc_dec_reg_rd(adp, (0x00380000 | (mem_off & 0x0007FFFF)));
  34. }
  35. static inline void crystalhd_dram_wr(struct crystalhd_adp *adp, uint32_t mem_off, uint32_t val)
  36. {
  37. crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19));
  38. bc_dec_reg_wr(adp, (0x00380000 | (mem_off & 0x0007FFFF)), val);
  39. }
  40. static inline enum BC_STATUS bc_chk_dram_range(struct crystalhd_adp *adp, uint32_t start_off, uint32_t cnt)
  41. {
  42. return BC_STS_SUCCESS;
  43. }
  44. static struct crystalhd_dio_req *crystalhd_alloc_dio(struct crystalhd_adp *adp)
  45. {
  46. unsigned long flags = 0;
  47. struct crystalhd_dio_req *temp = NULL;
  48. if (!adp) {
  49. BCMLOG_ERR("Invalid Arg!!\n");
  50. return temp;
  51. }
  52. spin_lock_irqsave(&adp->lock, flags);
  53. temp = adp->ua_map_free_head;
  54. if (temp)
  55. adp->ua_map_free_head = adp->ua_map_free_head->next;
  56. spin_unlock_irqrestore(&adp->lock, flags);
  57. return temp;
  58. }
  59. static void crystalhd_free_dio(struct crystalhd_adp *adp, struct crystalhd_dio_req *dio)
  60. {
  61. unsigned long flags = 0;
  62. if (!adp || !dio)
  63. return;
  64. spin_lock_irqsave(&adp->lock, flags);
  65. dio->sig = crystalhd_dio_inv;
  66. dio->page_cnt = 0;
  67. dio->fb_size = 0;
  68. memset(&dio->uinfo, 0, sizeof(dio->uinfo));
  69. dio->next = adp->ua_map_free_head;
  70. adp->ua_map_free_head = dio;
  71. spin_unlock_irqrestore(&adp->lock, flags);
  72. }
  73. static struct crystalhd_elem *crystalhd_alloc_elem(struct crystalhd_adp *adp)
  74. {
  75. unsigned long flags = 0;
  76. struct crystalhd_elem *temp = NULL;
  77. if (!adp)
  78. return temp;
  79. spin_lock_irqsave(&adp->lock, flags);
  80. temp = adp->elem_pool_head;
  81. if (temp) {
  82. adp->elem_pool_head = adp->elem_pool_head->flink;
  83. memset(temp, 0, sizeof(*temp));
  84. }
  85. spin_unlock_irqrestore(&adp->lock, flags);
  86. return temp;
  87. }
  88. static void crystalhd_free_elem(struct crystalhd_adp *adp, struct crystalhd_elem *elem)
  89. {
  90. unsigned long flags = 0;
  91. if (!adp || !elem)
  92. return;
  93. spin_lock_irqsave(&adp->lock, flags);
  94. elem->flink = adp->elem_pool_head;
  95. adp->elem_pool_head = elem;
  96. spin_unlock_irqrestore(&adp->lock, flags);
  97. }
  98. static inline void crystalhd_set_sg(struct scatterlist *sg, struct page *page,
  99. unsigned int len, unsigned int offset)
  100. {
  101. sg_set_page(sg, page, len, offset);
  102. #ifdef CONFIG_X86_64
  103. sg->dma_length = len;
  104. #endif
  105. }
  106. static inline void crystalhd_init_sg(struct scatterlist *sg, unsigned int entries)
  107. {
  108. /* http://lkml.org/lkml/2007/11/27/68 */
  109. sg_init_table(sg, entries);
  110. }
  111. /*========================== Extern ========================================*/
  112. /**
  113. * bc_dec_reg_rd - Read 7412's device register.
  114. * @adp: Adapter instance
  115. * @reg_off: Register offset.
  116. *
  117. * Return:
  118. * 32bit value read
  119. *
  120. * 7412's device register read routine. This interface use
  121. * 7412's device access range mapped from BAR-2 (4M) of PCIe
  122. * configuration space.
  123. */
  124. uint32_t bc_dec_reg_rd(struct crystalhd_adp *adp, uint32_t reg_off)
  125. {
  126. if (!adp || (reg_off > adp->pci_mem_len)) {
  127. BCMLOG_ERR("dec_rd_reg_off outof range: 0x%08x\n", reg_off);
  128. return 0;
  129. }
  130. return readl(adp->addr + reg_off);
  131. }
  132. /**
  133. * bc_dec_reg_wr - Write 7412's device register
  134. * @adp: Adapter instance
  135. * @reg_off: Register offset.
  136. * @val: Dword value to be written.
  137. *
  138. * Return:
  139. * none.
  140. *
  141. * 7412's device register write routine. This interface use
  142. * 7412's device access range mapped from BAR-2 (4M) of PCIe
  143. * configuration space.
  144. */
  145. void bc_dec_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val)
  146. {
  147. if (!adp || (reg_off > adp->pci_mem_len)) {
  148. BCMLOG_ERR("dec_wr_reg_off outof range: 0x%08x\n", reg_off);
  149. return;
  150. }
  151. writel(val, adp->addr + reg_off);
  152. udelay(8);
  153. }
  154. /**
  155. * crystalhd_reg_rd - Read Link's device register.
  156. * @adp: Adapter instance
  157. * @reg_off: Register offset.
  158. *
  159. * Return:
  160. * 32bit value read
  161. *
  162. * Link device register read routine. This interface use
  163. * Link's device access range mapped from BAR-1 (64K) of PCIe
  164. * configuration space.
  165. *
  166. */
  167. uint32_t crystalhd_reg_rd(struct crystalhd_adp *adp, uint32_t reg_off)
  168. {
  169. if (!adp || (reg_off > adp->pci_i2o_len)) {
  170. BCMLOG_ERR("link_rd_reg_off outof range: 0x%08x\n", reg_off);
  171. return 0;
  172. }
  173. return readl(adp->i2o_addr + reg_off);
  174. }
  175. /**
  176. * crystalhd_reg_wr - Write Link's device register
  177. * @adp: Adapter instance
  178. * @reg_off: Register offset.
  179. * @val: Dword value to be written.
  180. *
  181. * Return:
  182. * none.
  183. *
  184. * Link device register write routine. This interface use
  185. * Link's device access range mapped from BAR-1 (64K) of PCIe
  186. * configuration space.
  187. *
  188. */
  189. void crystalhd_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val)
  190. {
  191. if (!adp || (reg_off > adp->pci_i2o_len)) {
  192. BCMLOG_ERR("link_wr_reg_off outof range: 0x%08x\n", reg_off);
  193. return;
  194. }
  195. writel(val, adp->i2o_addr + reg_off);
  196. }
  197. /**
  198. * crystalhd_mem_rd - Read data from 7412's DRAM area.
  199. * @adp: Adapter instance
  200. * @start_off: Start offset.
  201. * @dw_cnt: Count in dwords.
  202. * @rd_buff: Buffer to copy the data from dram.
  203. *
  204. * Return:
  205. * Status.
  206. *
  207. * 7412's Dram read routine.
  208. */
  209. enum BC_STATUS crystalhd_mem_rd(struct crystalhd_adp *adp, uint32_t start_off,
  210. uint32_t dw_cnt, uint32_t *rd_buff)
  211. {
  212. uint32_t ix = 0;
  213. if (!adp || !rd_buff ||
  214. (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) {
  215. BCMLOG_ERR("Invalid arg\n");
  216. return BC_STS_INV_ARG;
  217. }
  218. for (ix = 0; ix < dw_cnt; ix++)
  219. rd_buff[ix] = crystalhd_dram_rd(adp, (start_off + (ix * 4)));
  220. return BC_STS_SUCCESS;
  221. }
  222. /**
  223. * crystalhd_mem_wr - Write data to 7412's DRAM area.
  224. * @adp: Adapter instance
  225. * @start_off: Start offset.
  226. * @dw_cnt: Count in dwords.
  227. * @wr_buff: Data Buffer to be written.
  228. *
  229. * Return:
  230. * Status.
  231. *
  232. * 7412's Dram write routine.
  233. */
  234. enum BC_STATUS crystalhd_mem_wr(struct crystalhd_adp *adp, uint32_t start_off,
  235. uint32_t dw_cnt, uint32_t *wr_buff)
  236. {
  237. uint32_t ix = 0;
  238. if (!adp || !wr_buff ||
  239. (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) {
  240. BCMLOG_ERR("Invalid arg\n");
  241. return BC_STS_INV_ARG;
  242. }
  243. for (ix = 0; ix < dw_cnt; ix++)
  244. crystalhd_dram_wr(adp, (start_off + (ix * 4)), wr_buff[ix]);
  245. return BC_STS_SUCCESS;
  246. }
  247. /**
  248. * crystalhd_pci_cfg_rd - PCIe config read
  249. * @adp: Adapter instance
  250. * @off: PCI config space offset.
  251. * @len: Size -- Byte, Word & dword.
  252. * @val: Value read
  253. *
  254. * Return:
  255. * Status.
  256. *
  257. * Get value from Link's PCIe config space.
  258. */
  259. enum BC_STATUS crystalhd_pci_cfg_rd(struct crystalhd_adp *adp, uint32_t off,
  260. uint32_t len, uint32_t *val)
  261. {
  262. enum BC_STATUS sts = BC_STS_SUCCESS;
  263. int rc = 0;
  264. if (!adp || !val) {
  265. BCMLOG_ERR("Invalid arg\n");
  266. return BC_STS_INV_ARG;
  267. }
  268. switch (len) {
  269. case 1:
  270. rc = pci_read_config_byte(adp->pdev, off, (u8 *)val);
  271. break;
  272. case 2:
  273. rc = pci_read_config_word(adp->pdev, off, (u16 *)val);
  274. break;
  275. case 4:
  276. rc = pci_read_config_dword(adp->pdev, off, (u32 *)val);
  277. break;
  278. default:
  279. rc = -EINVAL;
  280. sts = BC_STS_INV_ARG;
  281. BCMLOG_ERR("Invalid len:%d\n", len);
  282. }
  283. if (rc && (sts == BC_STS_SUCCESS))
  284. sts = BC_STS_ERROR;
  285. return sts;
  286. }
  287. /**
  288. * crystalhd_pci_cfg_wr - PCIe config write
  289. * @adp: Adapter instance
  290. * @off: PCI config space offset.
  291. * @len: Size -- Byte, Word & dword.
  292. * @val: Value to be written
  293. *
  294. * Return:
  295. * Status.
  296. *
  297. * Set value to Link's PCIe config space.
  298. */
  299. enum BC_STATUS crystalhd_pci_cfg_wr(struct crystalhd_adp *adp, uint32_t off,
  300. uint32_t len, uint32_t val)
  301. {
  302. enum BC_STATUS sts = BC_STS_SUCCESS;
  303. int rc = 0;
  304. if (!adp || !val) {
  305. BCMLOG_ERR("Invalid arg\n");
  306. return BC_STS_INV_ARG;
  307. }
  308. switch (len) {
  309. case 1:
  310. rc = pci_write_config_byte(adp->pdev, off, (u8)val);
  311. break;
  312. case 2:
  313. rc = pci_write_config_word(adp->pdev, off, (u16)val);
  314. break;
  315. case 4:
  316. rc = pci_write_config_dword(adp->pdev, off, val);
  317. break;
  318. default:
  319. rc = -EINVAL;
  320. sts = BC_STS_INV_ARG;
  321. BCMLOG_ERR("Invalid len:%d\n", len);
  322. }
  323. if (rc && (sts == BC_STS_SUCCESS))
  324. sts = BC_STS_ERROR;
  325. return sts;
  326. }
  327. /**
  328. * bc_kern_dma_alloc - Allocate memory for Dma rings
  329. * @adp: Adapter instance
  330. * @sz: Size of the memory to allocate.
  331. * @phy_addr: Physical address of the memory allocated.
  332. * Typedef to system's dma_addr_t (u64)
  333. *
  334. * Return:
  335. * Pointer to allocated memory..
  336. *
  337. * Wrapper to Linux kernel interface.
  338. *
  339. */
  340. void *bc_kern_dma_alloc(struct crystalhd_adp *adp, uint32_t sz,
  341. dma_addr_t *phy_addr)
  342. {
  343. void *temp = NULL;
  344. if (!adp || !sz || !phy_addr) {
  345. BCMLOG_ERR("Invalide Arg..\n");
  346. return temp;
  347. }
  348. temp = pci_alloc_consistent(adp->pdev, sz, phy_addr);
  349. if (temp)
  350. memset(temp, 0, sz);
  351. return temp;
  352. }
  353. /**
  354. * bc_kern_dma_free - Release Dma ring memory.
  355. * @adp: Adapter instance
  356. * @sz: Size of the memory to allocate.
  357. * @ka: Kernel virtual address returned during _dio_alloc()
  358. * @phy_addr: Physical address of the memory allocated.
  359. * Typedef to system's dma_addr_t (u64)
  360. *
  361. * Return:
  362. * none.
  363. */
  364. void bc_kern_dma_free(struct crystalhd_adp *adp, uint32_t sz, void *ka,
  365. dma_addr_t phy_addr)
  366. {
  367. if (!adp || !ka || !sz || !phy_addr) {
  368. BCMLOG_ERR("Invalide Arg..\n");
  369. return;
  370. }
  371. pci_free_consistent(adp->pdev, sz, ka, phy_addr);
  372. }
  373. /**
  374. * crystalhd_create_dioq - Create Generic DIO queue
  375. * @adp: Adapter instance
  376. * @dioq_hnd: Handle to the dio queue created
  377. * @cb : Optional - Call back To free the element.
  378. * @cbctx: Context to pass to callback.
  379. *
  380. * Return:
  381. * status
  382. *
  383. * Initialize Generic DIO queue to hold any data. Callback
  384. * will be used to free elements while deleting the queue.
  385. */
  386. enum BC_STATUS crystalhd_create_dioq(struct crystalhd_adp *adp,
  387. struct crystalhd_dioq **dioq_hnd,
  388. crystalhd_data_free_cb cb, void *cbctx)
  389. {
  390. struct crystalhd_dioq *dioq = NULL;
  391. if (!adp || !dioq_hnd) {
  392. BCMLOG_ERR("Invalid arg!!\n");
  393. return BC_STS_INV_ARG;
  394. }
  395. dioq = kzalloc(sizeof(*dioq), GFP_KERNEL);
  396. if (!dioq)
  397. return BC_STS_INSUFF_RES;
  398. spin_lock_init(&dioq->lock);
  399. dioq->sig = BC_LINK_DIOQ_SIG;
  400. dioq->head = (struct crystalhd_elem *)&dioq->head;
  401. dioq->tail = (struct crystalhd_elem *)&dioq->head;
  402. crystalhd_create_event(&dioq->event);
  403. dioq->adp = adp;
  404. dioq->data_rel_cb = cb;
  405. dioq->cb_context = cbctx;
  406. *dioq_hnd = dioq;
  407. return BC_STS_SUCCESS;
  408. }
  409. /**
  410. * crystalhd_delete_dioq - Delete Generic DIO queue
  411. * @adp: Adapter instance
  412. * @dioq: DIOQ instance..
  413. *
  414. * Return:
  415. * None.
  416. *
  417. * Release Generic DIO queue. This function will remove
  418. * all the entries from the Queue and will release data
  419. * by calling the call back provided during creation.
  420. *
  421. */
  422. void crystalhd_delete_dioq(struct crystalhd_adp *adp, struct crystalhd_dioq *dioq)
  423. {
  424. void *temp;
  425. if (!dioq || (dioq->sig != BC_LINK_DIOQ_SIG))
  426. return;
  427. do {
  428. temp = crystalhd_dioq_fetch(dioq);
  429. if (temp && dioq->data_rel_cb)
  430. dioq->data_rel_cb(dioq->cb_context, temp);
  431. } while (temp);
  432. dioq->sig = 0;
  433. kfree(dioq);
  434. }
  435. /**
  436. * crystalhd_dioq_add - Add new DIO request element.
  437. * @ioq: DIO queue instance
  438. * @t: DIO request to be added.
  439. * @wake: True - Wake up suspended process.
  440. * @tag: Special tag to assign - For search and get.
  441. *
  442. * Return:
  443. * Status.
  444. *
  445. * Insert new element to Q tail.
  446. */
  447. enum BC_STATUS crystalhd_dioq_add(struct crystalhd_dioq *ioq, void *data,
  448. bool wake, uint32_t tag)
  449. {
  450. unsigned long flags = 0;
  451. struct crystalhd_elem *tmp;
  452. if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !data) {
  453. BCMLOG_ERR("Invalid arg!!\n");
  454. return BC_STS_INV_ARG;
  455. }
  456. tmp = crystalhd_alloc_elem(ioq->adp);
  457. if (!tmp) {
  458. BCMLOG_ERR("No free elements.\n");
  459. return BC_STS_INSUFF_RES;
  460. }
  461. tmp->data = data;
  462. tmp->tag = tag;
  463. spin_lock_irqsave(&ioq->lock, flags);
  464. tmp->flink = (struct crystalhd_elem *)&ioq->head;
  465. tmp->blink = ioq->tail;
  466. tmp->flink->blink = tmp;
  467. tmp->blink->flink = tmp;
  468. ioq->count++;
  469. spin_unlock_irqrestore(&ioq->lock, flags);
  470. if (wake)
  471. crystalhd_set_event(&ioq->event);
  472. return BC_STS_SUCCESS;
  473. }
  474. /**
  475. * crystalhd_dioq_fetch - Fetch element from head.
  476. * @ioq: DIO queue instance
  477. *
  478. * Return:
  479. * data element from the head..
  480. *
  481. * Remove an element from Queue.
  482. */
  483. void *crystalhd_dioq_fetch(struct crystalhd_dioq *ioq)
  484. {
  485. unsigned long flags = 0;
  486. struct crystalhd_elem *tmp;
  487. struct crystalhd_elem *ret = NULL;
  488. void *data = NULL;
  489. if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) {
  490. BCMLOG_ERR("Invalid arg!!\n");
  491. return data;
  492. }
  493. spin_lock_irqsave(&ioq->lock, flags);
  494. tmp = ioq->head;
  495. if (tmp != (struct crystalhd_elem *)&ioq->head) {
  496. ret = tmp;
  497. tmp->flink->blink = tmp->blink;
  498. tmp->blink->flink = tmp->flink;
  499. ioq->count--;
  500. }
  501. spin_unlock_irqrestore(&ioq->lock, flags);
  502. if (ret) {
  503. data = ret->data;
  504. crystalhd_free_elem(ioq->adp, ret);
  505. }
  506. return data;
  507. }
  508. /**
  509. * crystalhd_dioq_find_and_fetch - Search the tag and Fetch element
  510. * @ioq: DIO queue instance
  511. * @tag: Tag to search for.
  512. *
  513. * Return:
  514. * element from the head..
  515. *
  516. * Search TAG and remove the element.
  517. */
  518. void *crystalhd_dioq_find_and_fetch(struct crystalhd_dioq *ioq, uint32_t tag)
  519. {
  520. unsigned long flags = 0;
  521. struct crystalhd_elem *tmp;
  522. struct crystalhd_elem *ret = NULL;
  523. void *data = NULL;
  524. if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) {
  525. BCMLOG_ERR("Invalid arg!!\n");
  526. return data;
  527. }
  528. spin_lock_irqsave(&ioq->lock, flags);
  529. tmp = ioq->head;
  530. while (tmp != (struct crystalhd_elem *)&ioq->head) {
  531. if (tmp->tag == tag) {
  532. ret = tmp;
  533. tmp->flink->blink = tmp->blink;
  534. tmp->blink->flink = tmp->flink;
  535. ioq->count--;
  536. break;
  537. }
  538. tmp = tmp->flink;
  539. }
  540. spin_unlock_irqrestore(&ioq->lock, flags);
  541. if (ret) {
  542. data = ret->data;
  543. crystalhd_free_elem(ioq->adp, ret);
  544. }
  545. return data;
  546. }
  547. /**
  548. * crystalhd_dioq_fetch_wait - Fetch element from Head.
  549. * @ioq: DIO queue instance
  550. * @to_secs: Wait timeout in seconds..
  551. *
  552. * Return:
  553. * element from the head..
  554. *
  555. * Return element from head if Q is not empty. Wait for new element
  556. * if Q is empty for Timeout seconds.
  557. */
  558. void *crystalhd_dioq_fetch_wait(struct crystalhd_dioq *ioq, uint32_t to_secs,
  559. uint32_t *sig_pend)
  560. {
  561. unsigned long flags = 0;
  562. int rc = 0, count;
  563. void *tmp = NULL;
  564. if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !to_secs || !sig_pend) {
  565. BCMLOG_ERR("Invalid arg!!\n");
  566. return tmp;
  567. }
  568. count = to_secs;
  569. spin_lock_irqsave(&ioq->lock, flags);
  570. while ((ioq->count == 0) && count) {
  571. spin_unlock_irqrestore(&ioq->lock, flags);
  572. crystalhd_wait_on_event(&ioq->event, (ioq->count > 0), 1000, rc, 0);
  573. if (rc == 0) {
  574. goto out;
  575. } else if (rc == -EINTR) {
  576. BCMLOG(BCMLOG_INFO, "Cancelling fetch wait\n");
  577. *sig_pend = 1;
  578. return tmp;
  579. }
  580. spin_lock_irqsave(&ioq->lock, flags);
  581. count--;
  582. }
  583. spin_unlock_irqrestore(&ioq->lock, flags);
  584. out:
  585. return crystalhd_dioq_fetch(ioq);
  586. }
  587. /**
  588. * crystalhd_map_dio - Map user address for DMA
  589. * @adp: Adapter instance
  590. * @ubuff: User buffer to map.
  591. * @ubuff_sz: User buffer size.
  592. * @uv_offset: UV buffer offset.
  593. * @en_422mode: TRUE:422 FALSE:420 Capture mode.
  594. * @dir_tx: TRUE for Tx (To device from host)
  595. * @dio_hnd: Handle to mapped DIO request.
  596. *
  597. * Return:
  598. * Status.
  599. *
  600. * This routine maps user address and lock pages for DMA.
  601. *
  602. */
  603. enum BC_STATUS crystalhd_map_dio(struct crystalhd_adp *adp, void *ubuff,
  604. uint32_t ubuff_sz, uint32_t uv_offset,
  605. bool en_422mode, bool dir_tx,
  606. struct crystalhd_dio_req **dio_hnd)
  607. {
  608. struct crystalhd_dio_req *dio;
  609. /* FIXME: jarod: should some of these unsigned longs be uint32_t or uintptr_t? */
  610. unsigned long start = 0, end = 0, uaddr = 0, count = 0;
  611. unsigned long spsz = 0, uv_start = 0;
  612. int i = 0, rw = 0, res = 0, nr_pages = 0, skip_fb_sg = 0;
  613. if (!adp || !ubuff || !ubuff_sz || !dio_hnd) {
  614. BCMLOG_ERR("Invalid arg\n");
  615. return BC_STS_INV_ARG;
  616. }
  617. /* Compute pages */
  618. uaddr = (unsigned long)ubuff;
  619. count = (unsigned long)ubuff_sz;
  620. end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
  621. start = uaddr >> PAGE_SHIFT;
  622. nr_pages = end - start;
  623. if (!count || ((uaddr + count) < uaddr)) {
  624. BCMLOG_ERR("User addr overflow!!\n");
  625. return BC_STS_INV_ARG;
  626. }
  627. dio = crystalhd_alloc_dio(adp);
  628. if (!dio) {
  629. BCMLOG_ERR("dio pool empty..\n");
  630. return BC_STS_INSUFF_RES;
  631. }
  632. if (dir_tx) {
  633. rw = WRITE;
  634. dio->direction = DMA_TO_DEVICE;
  635. } else {
  636. rw = READ;
  637. dio->direction = DMA_FROM_DEVICE;
  638. }
  639. if (nr_pages > dio->max_pages) {
  640. BCMLOG_ERR("max_pages(%d) exceeded(%d)!!\n",
  641. dio->max_pages, nr_pages);
  642. crystalhd_unmap_dio(adp, dio);
  643. return BC_STS_INSUFF_RES;
  644. }
  645. if (uv_offset) {
  646. uv_start = (uaddr + (unsigned long)uv_offset) >> PAGE_SHIFT;
  647. dio->uinfo.uv_sg_ix = uv_start - start;
  648. dio->uinfo.uv_sg_off = ((uaddr + (unsigned long)uv_offset) & ~PAGE_MASK);
  649. }
  650. dio->fb_size = ubuff_sz & 0x03;
  651. if (dio->fb_size) {
  652. res = copy_from_user(dio->fb_va,
  653. (void *)(uaddr + count - dio->fb_size),
  654. dio->fb_size);
  655. if (res) {
  656. BCMLOG_ERR("failed %d to copy %u fill bytes from %p\n",
  657. res, dio->fb_size,
  658. (void *)(uaddr + count-dio->fb_size));
  659. crystalhd_unmap_dio(adp, dio);
  660. return BC_STS_INSUFF_RES;
  661. }
  662. }
  663. down_read(&current->mm->mmap_sem);
  664. res = get_user_pages(current, current->mm, uaddr, nr_pages, rw == READ,
  665. 0, dio->pages, NULL);
  666. up_read(&current->mm->mmap_sem);
  667. /* Save for release..*/
  668. dio->sig = crystalhd_dio_locked;
  669. if (res < nr_pages) {
  670. BCMLOG_ERR("get pages failed: %d-%d\n", nr_pages, res);
  671. dio->page_cnt = res;
  672. crystalhd_unmap_dio(adp, dio);
  673. return BC_STS_ERROR;
  674. }
  675. dio->page_cnt = nr_pages;
  676. /* Get scatter/gather */
  677. crystalhd_init_sg(dio->sg, dio->page_cnt);
  678. crystalhd_set_sg(&dio->sg[0], dio->pages[0], 0, uaddr & ~PAGE_MASK);
  679. if (nr_pages > 1) {
  680. dio->sg[0].length = PAGE_SIZE - dio->sg[0].offset;
  681. #ifdef CONFIG_X86_64
  682. dio->sg[0].dma_length = dio->sg[0].length;
  683. #endif
  684. count -= dio->sg[0].length;
  685. for (i = 1; i < nr_pages; i++) {
  686. if (count < 4) {
  687. spsz = count;
  688. skip_fb_sg = 1;
  689. } else {
  690. spsz = (count < PAGE_SIZE) ?
  691. (count & ~0x03) : PAGE_SIZE;
  692. }
  693. crystalhd_set_sg(&dio->sg[i], dio->pages[i], spsz, 0);
  694. count -= spsz;
  695. }
  696. } else {
  697. if (count < 4) {
  698. dio->sg[0].length = count;
  699. skip_fb_sg = 1;
  700. } else {
  701. dio->sg[0].length = count - dio->fb_size;
  702. }
  703. #ifdef CONFIG_X86_64
  704. dio->sg[0].dma_length = dio->sg[0].length;
  705. #endif
  706. }
  707. dio->sg_cnt = pci_map_sg(adp->pdev, dio->sg,
  708. dio->page_cnt, dio->direction);
  709. if (dio->sg_cnt <= 0) {
  710. BCMLOG_ERR("sg map %d-%d\n", dio->sg_cnt, dio->page_cnt);
  711. crystalhd_unmap_dio(adp, dio);
  712. return BC_STS_ERROR;
  713. }
  714. if (dio->sg_cnt && skip_fb_sg)
  715. dio->sg_cnt -= 1;
  716. dio->sig = crystalhd_dio_sg_mapped;
  717. /* Fill in User info.. */
  718. dio->uinfo.xfr_len = ubuff_sz;
  719. dio->uinfo.xfr_buff = ubuff;
  720. dio->uinfo.uv_offset = uv_offset;
  721. dio->uinfo.b422mode = en_422mode;
  722. dio->uinfo.dir_tx = dir_tx;
  723. *dio_hnd = dio;
  724. return BC_STS_SUCCESS;
  725. }
  726. /**
  727. * crystalhd_unmap_sgl - Release mapped resources
  728. * @adp: Adapter instance
  729. * @dio: DIO request instance
  730. *
  731. * Return:
  732. * Status.
  733. *
  734. * This routine is to unmap the user buffer pages.
  735. */
  736. enum BC_STATUS crystalhd_unmap_dio(struct crystalhd_adp *adp, struct crystalhd_dio_req *dio)
  737. {
  738. struct page *page = NULL;
  739. int j = 0;
  740. if (!adp || !dio) {
  741. BCMLOG_ERR("Invalid arg\n");
  742. return BC_STS_INV_ARG;
  743. }
  744. if ((dio->page_cnt > 0) && (dio->sig != crystalhd_dio_inv)) {
  745. for (j = 0; j < dio->page_cnt; j++) {
  746. page = dio->pages[j];
  747. if (page) {
  748. if (!PageReserved(page) &&
  749. (dio->direction == DMA_FROM_DEVICE))
  750. SetPageDirty(page);
  751. page_cache_release(page);
  752. }
  753. }
  754. }
  755. if (dio->sig == crystalhd_dio_sg_mapped)
  756. pci_unmap_sg(adp->pdev, dio->sg, dio->page_cnt, dio->direction);
  757. crystalhd_free_dio(adp, dio);
  758. return BC_STS_SUCCESS;
  759. }
  760. /**
  761. * crystalhd_create_dio_pool - Allocate mem pool for DIO management.
  762. * @adp: Adapter instance
  763. * @max_pages: Max pages for size calculation.
  764. *
  765. * Return:
  766. * system error.
  767. *
  768. * This routine creates a memory pool to hold dio context for
  769. * for HW Direct IO operation.
  770. */
  771. int crystalhd_create_dio_pool(struct crystalhd_adp *adp, uint32_t max_pages)
  772. {
  773. uint32_t asz = 0, i = 0;
  774. uint8_t *temp;
  775. struct crystalhd_dio_req *dio;
  776. if (!adp || !max_pages) {
  777. BCMLOG_ERR("Invalid Arg!!\n");
  778. return -EINVAL;
  779. }
  780. /* Get dma memory for fill byte handling..*/
  781. adp->fill_byte_pool = pci_pool_create("crystalhd_fbyte",
  782. adp->pdev, 8, 8, 0);
  783. if (!adp->fill_byte_pool) {
  784. BCMLOG_ERR("failed to create fill byte pool\n");
  785. return -ENOMEM;
  786. }
  787. /* Get the max size from user based on 420/422 modes */
  788. asz = (sizeof(*dio->pages) * max_pages) +
  789. (sizeof(*dio->sg) * max_pages) + sizeof(*dio);
  790. BCMLOG(BCMLOG_DBG, "Initializing Dio pool %d %d %x %p\n",
  791. BC_LINK_SG_POOL_SZ, max_pages, asz, adp->fill_byte_pool);
  792. for (i = 0; i < BC_LINK_SG_POOL_SZ; i++) {
  793. temp = kzalloc(asz, GFP_KERNEL);
  794. if ((temp) == NULL) {
  795. BCMLOG_ERR("Failed to alloc %d mem\n", asz);
  796. return -ENOMEM;
  797. }
  798. dio = (struct crystalhd_dio_req *)temp;
  799. temp += sizeof(*dio);
  800. dio->pages = (struct page **)temp;
  801. temp += (sizeof(*dio->pages) * max_pages);
  802. dio->sg = (struct scatterlist *)temp;
  803. dio->max_pages = max_pages;
  804. dio->fb_va = pci_pool_alloc(adp->fill_byte_pool, GFP_KERNEL,
  805. &dio->fb_pa);
  806. if (!dio->fb_va) {
  807. BCMLOG_ERR("fill byte alloc failed.\n");
  808. return -ENOMEM;
  809. }
  810. crystalhd_free_dio(adp, dio);
  811. }
  812. return 0;
  813. }
  814. /**
  815. * crystalhd_destroy_dio_pool - Release DIO mem pool.
  816. * @adp: Adapter instance
  817. *
  818. * Return:
  819. * none.
  820. *
  821. * This routine releases dio memory pool during close.
  822. */
  823. void crystalhd_destroy_dio_pool(struct crystalhd_adp *adp)
  824. {
  825. struct crystalhd_dio_req *dio;
  826. int count = 0;
  827. if (!adp) {
  828. BCMLOG_ERR("Invalid Arg!!\n");
  829. return;
  830. }
  831. do {
  832. dio = crystalhd_alloc_dio(adp);
  833. if (dio) {
  834. if (dio->fb_va)
  835. pci_pool_free(adp->fill_byte_pool,
  836. dio->fb_va, dio->fb_pa);
  837. count++;
  838. kfree(dio);
  839. }
  840. } while (dio);
  841. if (adp->fill_byte_pool) {
  842. pci_pool_destroy(adp->fill_byte_pool);
  843. adp->fill_byte_pool = NULL;
  844. }
  845. BCMLOG(BCMLOG_DBG, "Released dio pool %d\n", count);
  846. }
  847. /**
  848. * crystalhd_create_elem_pool - List element pool creation.
  849. * @adp: Adapter instance
  850. * @pool_size: Number of elements in the pool.
  851. *
  852. * Return:
  853. * 0 - success, <0 error
  854. *
  855. * Create general purpose list element pool to hold pending,
  856. * and active requests.
  857. */
  858. int __devinit crystalhd_create_elem_pool(struct crystalhd_adp *adp,
  859. uint32_t pool_size)
  860. {
  861. uint32_t i;
  862. struct crystalhd_elem *temp;
  863. if (!adp || !pool_size)
  864. return -EINVAL;
  865. for (i = 0; i < pool_size; i++) {
  866. temp = kzalloc(sizeof(*temp), GFP_KERNEL);
  867. if (!temp) {
  868. BCMLOG_ERR("kalloc failed\n");
  869. return -ENOMEM;
  870. }
  871. crystalhd_free_elem(adp, temp);
  872. }
  873. BCMLOG(BCMLOG_DBG, "allocated %d elem\n", pool_size);
  874. return 0;
  875. }
  876. /**
  877. * crystalhd_delete_elem_pool - List element pool deletion.
  878. * @adp: Adapter instance
  879. *
  880. * Return:
  881. * none
  882. *
  883. * Delete general purpose list element pool.
  884. */
  885. void crystalhd_delete_elem_pool(struct crystalhd_adp *adp)
  886. {
  887. struct crystalhd_elem *temp;
  888. int dbg_cnt = 0;
  889. if (!adp)
  890. return;
  891. do {
  892. temp = crystalhd_alloc_elem(adp);
  893. if (temp) {
  894. kfree(temp);
  895. dbg_cnt++;
  896. }
  897. } while (temp);
  898. BCMLOG(BCMLOG_DBG, "released %d elem\n", dbg_cnt);
  899. }
  900. /*================ Debug support routines.. ================================*/
  901. void crystalhd_show_buffer(uint32_t off, uint8_t *buff, uint32_t dwcount)
  902. {
  903. uint32_t i, k = 1;
  904. for (i = 0; i < dwcount; i++) {
  905. if (k == 1)
  906. BCMLOG(BCMLOG_DATA, "0x%08X : ", off);
  907. BCMLOG(BCMLOG_DATA, " 0x%08X ", *((uint32_t *)buff));
  908. buff += sizeof(uint32_t);
  909. off += sizeof(uint32_t);
  910. k++;
  911. if ((i == dwcount - 1) || (k > 4)) {
  912. BCMLOG(BCMLOG_DATA, "\n");
  913. k = 1;
  914. }
  915. }
  916. }