aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/crystalhd/crystalhd_misc.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.c1044
1 files changed, 0 insertions, 1044 deletions
diff --git a/drivers/staging/crystalhd/crystalhd_misc.c b/drivers/staging/crystalhd/crystalhd_misc.c
deleted file mode 100644
index 3aabf75b7d97..000000000000
--- a/drivers/staging/crystalhd/crystalhd_misc.c
+++ /dev/null
@@ -1,1044 +0,0 @@
-/***************************************************************************
- * Copyright (c) 2005-2009, Broadcom Corporation.
- *
- * Name: crystalhd_misc . c
- *
- * Description:
- * BCM70012 Linux driver misc routines.
- *
- * HISTORY:
- *
- **********************************************************************
- * This file is part of the crystalhd device driver.
- *
- * This driver is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 2 of the License.
- *
- * This driver is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this driver. If not, see <http://www.gnu.org/licenses/>.
- **********************************************************************/
-
-#include "crystalhd.h"
-
-#include <linux/slab.h>
-
-uint32_t g_linklog_level;
-
-static inline uint32_t crystalhd_dram_rd(struct crystalhd_adp *adp,
- uint32_t mem_off)
-{
- crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19));
- return bc_dec_reg_rd(adp, (0x00380000 | (mem_off & 0x0007FFFF)));
-}
-
-static inline void crystalhd_dram_wr(struct crystalhd_adp *adp,
- uint32_t mem_off, uint32_t val)
-{
- crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19));
- bc_dec_reg_wr(adp, (0x00380000 | (mem_off & 0x0007FFFF)), val);
-}
-
-static inline enum BC_STATUS bc_chk_dram_range(struct crystalhd_adp *adp,
- uint32_t start_off, uint32_t cnt)
-{
- return BC_STS_SUCCESS;
-}
-
-static struct crystalhd_dio_req *crystalhd_alloc_dio(struct crystalhd_adp *adp)
-{
- unsigned long flags = 0;
- struct crystalhd_dio_req *temp = NULL;
-
- if (!adp) {
- BCMLOG_ERR("Invalid Arg!!\n");
- return temp;
- }
-
- spin_lock_irqsave(&adp->lock, flags);
- temp = adp->ua_map_free_head;
- if (temp)
- adp->ua_map_free_head = adp->ua_map_free_head->next;
- spin_unlock_irqrestore(&adp->lock, flags);
-
- return temp;
-}
-
-static void crystalhd_free_dio(struct crystalhd_adp *adp,
- struct crystalhd_dio_req *dio)
-{
- unsigned long flags = 0;
-
- if (!adp || !dio)
- return;
- spin_lock_irqsave(&adp->lock, flags);
- dio->sig = crystalhd_dio_inv;
- dio->page_cnt = 0;
- dio->fb_size = 0;
- memset(&dio->uinfo, 0, sizeof(dio->uinfo));
- dio->next = adp->ua_map_free_head;
- adp->ua_map_free_head = dio;
- spin_unlock_irqrestore(&adp->lock, flags);
-}
-
-static struct crystalhd_elem *crystalhd_alloc_elem(struct crystalhd_adp *adp)
-{
- unsigned long flags = 0;
- struct crystalhd_elem *temp = NULL;
-
- if (!adp)
- return temp;
- spin_lock_irqsave(&adp->lock, flags);
- temp = adp->elem_pool_head;
- if (temp) {
- adp->elem_pool_head = adp->elem_pool_head->flink;
- memset(temp, 0, sizeof(*temp));
- }
- spin_unlock_irqrestore(&adp->lock, flags);
-
- return temp;
-}
-static void crystalhd_free_elem(struct crystalhd_adp *adp,
- struct crystalhd_elem *elem)
-{
- unsigned long flags = 0;
-
- if (!adp || !elem)
- return;
- spin_lock_irqsave(&adp->lock, flags);
- elem->flink = adp->elem_pool_head;
- adp->elem_pool_head = elem;
- spin_unlock_irqrestore(&adp->lock, flags);
-}
-
-static inline void crystalhd_set_sg(struct scatterlist *sg, struct page *page,
- unsigned int len, unsigned int offset)
-{
- sg_set_page(sg, page, len, offset);
-#ifdef CONFIG_X86_64
- sg->dma_length = len;
-#endif
-}
-
-static inline void crystalhd_init_sg(struct scatterlist *sg,
- unsigned int entries)
-{
- /* http://lkml.org/lkml/2007/11/27/68 */
- sg_init_table(sg, entries);
-}
-
-/*========================== Extern ========================================*/
-/**
- * bc_dec_reg_rd - Read 7412's device register.
- * @adp: Adapter instance
- * @reg_off: Register offset.
- *
- * Return:
- * 32bit value read
- *
- * 7412's device register read routine. This interface use
- * 7412's device access range mapped from BAR-2 (4M) of PCIe
- * configuration space.
- */
-uint32_t bc_dec_reg_rd(struct crystalhd_adp *adp, uint32_t reg_off)
-{
- if (!adp || (reg_off > adp->pci_mem_len)) {
- BCMLOG_ERR("dec_rd_reg_off outof range: 0x%08x\n", reg_off);
- return 0;
- }
-
- return readl(adp->addr + reg_off);
-}
-
-/**
- * bc_dec_reg_wr - Write 7412's device register
- * @adp: Adapter instance
- * @reg_off: Register offset.
- * @val: Dword value to be written.
- *
- * Return:
- * none.
- *
- * 7412's device register write routine. This interface use
- * 7412's device access range mapped from BAR-2 (4M) of PCIe
- * configuration space.
- */
-void bc_dec_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val)
-{
- if (!adp || (reg_off > adp->pci_mem_len)) {
- BCMLOG_ERR("dec_wr_reg_off outof range: 0x%08x\n", reg_off);
- return;
- }
- writel(val, adp->addr + reg_off);
- udelay(8);
-}
-
-/**
- * crystalhd_reg_rd - Read Link's device register.
- * @adp: Adapter instance
- * @reg_off: Register offset.
- *
- * Return:
- * 32bit value read
- *
- * Link device register read routine. This interface use
- * Link's device access range mapped from BAR-1 (64K) of PCIe
- * configuration space.
- *
- */
-uint32_t crystalhd_reg_rd(struct crystalhd_adp *adp, uint32_t reg_off)
-{
- if (!adp || (reg_off > adp->pci_i2o_len)) {
- BCMLOG_ERR("link_rd_reg_off outof range: 0x%08x\n", reg_off);
- return 0;
- }
- return readl(adp->i2o_addr + reg_off);
-}
-
-/**
- * crystalhd_reg_wr - Write Link's device register
- * @adp: Adapter instance
- * @reg_off: Register offset.
- * @val: Dword value to be written.
- *
- * Return:
- * none.
- *
- * Link device register write routine. This interface use
- * Link's device access range mapped from BAR-1 (64K) of PCIe
- * configuration space.
- *
- */
-void crystalhd_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off,
- uint32_t val)
-{
- if (!adp || (reg_off > adp->pci_i2o_len)) {
- BCMLOG_ERR("link_wr_reg_off outof range: 0x%08x\n", reg_off);
- return;
- }
- writel(val, adp->i2o_addr + reg_off);
-}
-
-/**
- * crystalhd_mem_rd - Read data from 7412's DRAM area.
- * @adp: Adapter instance
- * @start_off: Start offset.
- * @dw_cnt: Count in dwords.
- * @rd_buff: Buffer to copy the data from dram.
- *
- * Return:
- * Status.
- *
- * 7412's Dram read routine.
- */
-enum BC_STATUS crystalhd_mem_rd(struct crystalhd_adp *adp, uint32_t start_off,
- uint32_t dw_cnt, uint32_t *rd_buff)
-{
- uint32_t ix = 0;
-
- if (!adp || !rd_buff ||
- (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) {
- BCMLOG_ERR("Invalid arg\n");
- return BC_STS_INV_ARG;
- }
- for (ix = 0; ix < dw_cnt; ix++)
- rd_buff[ix] = crystalhd_dram_rd(adp, (start_off + (ix * 4)));
-
- return BC_STS_SUCCESS;
-}
-
-/**
- * crystalhd_mem_wr - Write data to 7412's DRAM area.
- * @adp: Adapter instance
- * @start_off: Start offset.
- * @dw_cnt: Count in dwords.
- * @wr_buff: Data Buffer to be written.
- *
- * Return:
- * Status.
- *
- * 7412's Dram write routine.
- */
-enum BC_STATUS crystalhd_mem_wr(struct crystalhd_adp *adp, uint32_t start_off,
- uint32_t dw_cnt, uint32_t *wr_buff)
-{
- uint32_t ix = 0;
-
- if (!adp || !wr_buff ||
- (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) {
- BCMLOG_ERR("Invalid arg\n");
- return BC_STS_INV_ARG;
- }
-
- for (ix = 0; ix < dw_cnt; ix++)
- crystalhd_dram_wr(adp, (start_off + (ix * 4)), wr_buff[ix]);
-
- return BC_STS_SUCCESS;
-}
-/**
- * crystalhd_pci_cfg_rd - PCIe config read
- * @adp: Adapter instance
- * @off: PCI config space offset.
- * @len: Size -- Byte, Word & dword.
- * @val: Value read
- *
- * Return:
- * Status.
- *
- * Get value from Link's PCIe config space.
- */
-enum BC_STATUS crystalhd_pci_cfg_rd(struct crystalhd_adp *adp, uint32_t off,
- uint32_t len, uint32_t *val)
-{
- enum BC_STATUS sts = BC_STS_SUCCESS;
- int rc = 0;
-
- if (!adp || !val) {
- BCMLOG_ERR("Invalid arg\n");
- return BC_STS_INV_ARG;
- }
-
- switch (len) {
- case 1:
- rc = pci_read_config_byte(adp->pdev, off, (u8 *)val);
- break;
- case 2:
- rc = pci_read_config_word(adp->pdev, off, (u16 *)val);
- break;
- case 4:
- rc = pci_read_config_dword(adp->pdev, off, (u32 *)val);
- break;
- default:
- rc = -EINVAL;
- sts = BC_STS_INV_ARG;
- BCMLOG_ERR("Invalid len:%d\n", len);
- }
-
- if (rc && (sts == BC_STS_SUCCESS))
- sts = BC_STS_ERROR;
-
- return sts;
-}
-
-/**
- * crystalhd_pci_cfg_wr - PCIe config write
- * @adp: Adapter instance
- * @off: PCI config space offset.
- * @len: Size -- Byte, Word & dword.
- * @val: Value to be written
- *
- * Return:
- * Status.
- *
- * Set value to Link's PCIe config space.
- */
-enum BC_STATUS crystalhd_pci_cfg_wr(struct crystalhd_adp *adp, uint32_t off,
- uint32_t len, uint32_t val)
-{
- enum BC_STATUS sts = BC_STS_SUCCESS;
- int rc = 0;
-
- if (!adp || !val) {
- BCMLOG_ERR("Invalid arg\n");
- return BC_STS_INV_ARG;
- }
-
- switch (len) {
- case 1:
- rc = pci_write_config_byte(adp->pdev, off, (u8)val);
- break;
- case 2:
- rc = pci_write_config_word(adp->pdev, off, (u16)val);
- break;
- case 4:
- rc = pci_write_config_dword(adp->pdev, off, val);
- break;
- default:
- rc = -EINVAL;
- sts = BC_STS_INV_ARG;
- BCMLOG_ERR("Invalid len:%d\n", len);
- }
-
- if (rc && (sts == BC_STS_SUCCESS))
- sts = BC_STS_ERROR;
-
- return sts;
-}
-
-/**
- * bc_kern_dma_alloc - Allocate memory for Dma rings
- * @adp: Adapter instance
- * @sz: Size of the memory to allocate.
- * @phy_addr: Physical address of the memory allocated.
- * Typedef to system's dma_addr_t (u64)
- *
- * Return:
- * Pointer to allocated memory..
- *
- * Wrapper to Linux kernel interface.
- *
- */
-void *bc_kern_dma_alloc(struct crystalhd_adp *adp, uint32_t sz,
- dma_addr_t *phy_addr)
-{
- void *temp = NULL;
-
- if (!adp || !sz || !phy_addr) {
- BCMLOG_ERR("Invalid Arg..\n");
- return temp;
- }
-
- temp = pci_alloc_consistent(adp->pdev, sz, phy_addr);
- if (temp)
- memset(temp, 0, sz);
-
- return temp;
-}
-
-/**
- * bc_kern_dma_free - Release Dma ring memory.
- * @adp: Adapter instance
- * @sz: Size of the memory to allocate.
- * @ka: Kernel virtual address returned during _dio_alloc()
- * @phy_addr: Physical address of the memory allocated.
- * Typedef to system's dma_addr_t (u64)
- *
- * Return:
- * none.
- */
-void bc_kern_dma_free(struct crystalhd_adp *adp, uint32_t sz, void *ka,
- dma_addr_t phy_addr)
-{
- if (!adp || !ka || !sz || !phy_addr) {
- BCMLOG_ERR("Invalid Arg..\n");
- return;
- }
-
- pci_free_consistent(adp->pdev, sz, ka, phy_addr);
-}
-
-/**
- * crystalhd_create_dioq - Create Generic DIO queue
- * @adp: Adapter instance
- * @dioq_hnd: Handle to the dio queue created
- * @cb : Optional - Call back To free the element.
- * @cbctx: Context to pass to callback.
- *
- * Return:
- * status
- *
- * Initialize Generic DIO queue to hold any data. Callback
- * will be used to free elements while deleting the queue.
- */
-enum BC_STATUS crystalhd_create_dioq(struct crystalhd_adp *adp,
- struct crystalhd_dioq **dioq_hnd,
- crystalhd_data_free_cb cb, void *cbctx)
-{
- struct crystalhd_dioq *dioq = NULL;
-
- if (!adp || !dioq_hnd) {
- BCMLOG_ERR("Invalid arg!!\n");
- return BC_STS_INV_ARG;
- }
-
- dioq = kzalloc(sizeof(*dioq), GFP_KERNEL);
- if (!dioq)
- return BC_STS_INSUFF_RES;
-
- spin_lock_init(&dioq->lock);
- dioq->sig = BC_LINK_DIOQ_SIG;
- dioq->head = (struct crystalhd_elem *)&dioq->head;
- dioq->tail = (struct crystalhd_elem *)&dioq->head;
- crystalhd_create_event(&dioq->event);
- dioq->adp = adp;
- dioq->data_rel_cb = cb;
- dioq->cb_context = cbctx;
- *dioq_hnd = dioq;
-
- return BC_STS_SUCCESS;
-}
-
-/**
- * crystalhd_delete_dioq - Delete Generic DIO queue
- * @adp: Adapter instance
- * @dioq: DIOQ instance..
- *
- * Return:
- * None.
- *
- * Release Generic DIO queue. This function will remove
- * all the entries from the Queue and will release data
- * by calling the call back provided during creation.
- *
- */
-void crystalhd_delete_dioq(struct crystalhd_adp *adp,
- struct crystalhd_dioq *dioq)
-{
- void *temp;
-
- if (!dioq || (dioq->sig != BC_LINK_DIOQ_SIG))
- return;
-
- do {
- temp = crystalhd_dioq_fetch(dioq);
- if (temp && dioq->data_rel_cb)
- dioq->data_rel_cb(dioq->cb_context, temp);
- } while (temp);
- dioq->sig = 0;
- kfree(dioq);
-}
-
-/**
- * crystalhd_dioq_add - Add new DIO request element.
- * @ioq: DIO queue instance
- * @t: DIO request to be added.
- * @wake: True - Wake up suspended process.
- * @tag: Special tag to assign - For search and get.
- *
- * Return:
- * Status.
- *
- * Insert new element to Q tail.
- */
-enum BC_STATUS crystalhd_dioq_add(struct crystalhd_dioq *ioq, void *data,
- bool wake, uint32_t tag)
-{
- unsigned long flags = 0;
- struct crystalhd_elem *tmp;
-
- if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !data) {
- BCMLOG_ERR("Invalid arg!!\n");
- return BC_STS_INV_ARG;
- }
-
- tmp = crystalhd_alloc_elem(ioq->adp);
- if (!tmp) {
- BCMLOG_ERR("No free elements.\n");
- return BC_STS_INSUFF_RES;
- }
-
- tmp->data = data;
- tmp->tag = tag;
- spin_lock_irqsave(&ioq->lock, flags);
- tmp->flink = (struct crystalhd_elem *)&ioq->head;
- tmp->blink = ioq->tail;
- tmp->flink->blink = tmp;
- tmp->blink->flink = tmp;
- ioq->count++;
- spin_unlock_irqrestore(&ioq->lock, flags);
-
- if (wake)
- crystalhd_set_event(&ioq->event);
-
- return BC_STS_SUCCESS;
-}
-
-/**
- * crystalhd_dioq_fetch - Fetch element from head.
- * @ioq: DIO queue instance
- *
- * Return:
- * data element from the head..
- *
- * Remove an element from Queue.
- */
-void *crystalhd_dioq_fetch(struct crystalhd_dioq *ioq)
-{
- unsigned long flags = 0;
- struct crystalhd_elem *tmp;
- struct crystalhd_elem *ret = NULL;
- void *data = NULL;
-
- if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) {
- BCMLOG_ERR("Invalid arg!!\n");
- return data;
- }
-
- spin_lock_irqsave(&ioq->lock, flags);
- tmp = ioq->head;
- if (tmp != (struct crystalhd_elem *)&ioq->head) {
- ret = tmp;
- tmp->flink->blink = tmp->blink;
- tmp->blink->flink = tmp->flink;
- ioq->count--;
- }
- spin_unlock_irqrestore(&ioq->lock, flags);
- if (ret) {
- data = ret->data;
- crystalhd_free_elem(ioq->adp, ret);
- }
-
- return data;
-}
-/**
- * crystalhd_dioq_find_and_fetch - Search the tag and Fetch element
- * @ioq: DIO queue instance
- * @tag: Tag to search for.
- *
- * Return:
- * element from the head..
- *
- * Search TAG and remove the element.
- */
-void *crystalhd_dioq_find_and_fetch(struct crystalhd_dioq *ioq, uint32_t tag)
-{
- unsigned long flags = 0;
- struct crystalhd_elem *tmp;
- struct crystalhd_elem *ret = NULL;
- void *data = NULL;
-
- if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) {
- BCMLOG_ERR("Invalid arg!!\n");
- return data;
- }
-
- spin_lock_irqsave(&ioq->lock, flags);
- tmp = ioq->head;
- while (tmp != (struct crystalhd_elem *)&ioq->head) {
- if (tmp->tag == tag) {
- ret = tmp;
- tmp->flink->blink = tmp->blink;
- tmp->blink->flink = tmp->flink;
- ioq->count--;
- break;
- }
- tmp = tmp->flink;
- }
- spin_unlock_irqrestore(&ioq->lock, flags);
-
- if (ret) {
- data = ret->data;
- crystalhd_free_elem(ioq->adp, ret);
- }
-
- return data;
-}
-
-/**
- * crystalhd_dioq_fetch_wait - Fetch element from Head.
- * @ioq: DIO queue instance
- * @to_secs: Wait timeout in seconds..
- *
- * Return:
- * element from the head..
- *
- * Return element from head if Q is not empty. Wait for new element
- * if Q is empty for Timeout seconds.
- */
-void *crystalhd_dioq_fetch_wait(struct crystalhd_dioq *ioq, uint32_t to_secs,
- uint32_t *sig_pend)
-{
- unsigned long flags = 0;
- int rc = 0, count;
- void *tmp = NULL;
-
- if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !to_secs || !sig_pend) {
- BCMLOG_ERR("Invalid arg!!\n");
- return tmp;
- }
-
- count = to_secs;
- spin_lock_irqsave(&ioq->lock, flags);
- while ((ioq->count == 0) && count) {
- spin_unlock_irqrestore(&ioq->lock, flags);
-
- crystalhd_wait_on_event(&ioq->event,
- (ioq->count > 0), 1000, rc, 0);
- if (rc == 0) {
- goto out;
- } else if (rc == -EINTR) {
- BCMLOG(BCMLOG_INFO, "Cancelling fetch wait\n");
- *sig_pend = 1;
- return tmp;
- }
- spin_lock_irqsave(&ioq->lock, flags);
- count--;
- }
- spin_unlock_irqrestore(&ioq->lock, flags);
-
-out:
- return crystalhd_dioq_fetch(ioq);
-}
-
-/**
- * crystalhd_map_dio - Map user address for DMA
- * @adp: Adapter instance
- * @ubuff: User buffer to map.
- * @ubuff_sz: User buffer size.
- * @uv_offset: UV buffer offset.
- * @en_422mode: TRUE:422 FALSE:420 Capture mode.
- * @dir_tx: TRUE for Tx (To device from host)
- * @dio_hnd: Handle to mapped DIO request.
- *
- * Return:
- * Status.
- *
- * This routine maps user address and lock pages for DMA.
- *
- */
-enum BC_STATUS crystalhd_map_dio(struct crystalhd_adp *adp, void *ubuff,
- uint32_t ubuff_sz, uint32_t uv_offset,
- bool en_422mode, bool dir_tx,
- struct crystalhd_dio_req **dio_hnd)
-{
- struct crystalhd_dio_req *dio;
- /* FIXME: jarod: should some of these
- unsigned longs be uint32_t or uintptr_t? */
- unsigned long start = 0, end = 0, uaddr = 0, count = 0;
- unsigned long spsz = 0, uv_start = 0;
- int i = 0, rw = 0, res = 0, nr_pages = 0, skip_fb_sg = 0;
-
- if (!adp || !ubuff || !ubuff_sz || !dio_hnd) {
- BCMLOG_ERR("Invalid arg\n");
- return BC_STS_INV_ARG;
- }
- /* Compute pages */
- uaddr = (unsigned long)ubuff;
- count = (unsigned long)ubuff_sz;
- end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
- start = uaddr >> PAGE_SHIFT;
- nr_pages = end - start;
-
- if (!count || ((uaddr + count) < uaddr)) {
- BCMLOG_ERR("User addr overflow!!\n");
- return BC_STS_INV_ARG;
- }
-
- dio = crystalhd_alloc_dio(adp);
- if (!dio) {
- BCMLOG_ERR("dio pool empty..\n");
- return BC_STS_INSUFF_RES;
- }
-
- if (dir_tx) {
- rw = WRITE;
- dio->direction = DMA_TO_DEVICE;
- } else {
- rw = READ;
- dio->direction = DMA_FROM_DEVICE;
- }
-
- if (nr_pages > dio->max_pages) {
- BCMLOG_ERR("max_pages(%d) exceeded(%d)!!\n",
- dio->max_pages, nr_pages);
- crystalhd_unmap_dio(adp, dio);
- return BC_STS_INSUFF_RES;
- }
-
- if (uv_offset) {
- uv_start = (uaddr + (unsigned long)uv_offset) >> PAGE_SHIFT;
- dio->uinfo.uv_sg_ix = uv_start - start;
- dio->uinfo.uv_sg_off = ((uaddr + (unsigned long)uv_offset) &
- ~PAGE_MASK);
- }
-
- dio->fb_size = ubuff_sz & 0x03;
- if (dio->fb_size) {
- res = copy_from_user(dio->fb_va,
- (void __user *)(uaddr + count - dio->fb_size),
- dio->fb_size);
- if (res) {
- BCMLOG_ERR("failed %d to copy %u fill bytes from %p\n",
- res, dio->fb_size,
- (void *)(uaddr + count-dio->fb_size));
- crystalhd_unmap_dio(adp, dio);
- return BC_STS_INSUFF_RES;
- }
- }
-
- down_read(&current->mm->mmap_sem);
- res = get_user_pages(current, current->mm, uaddr, nr_pages, rw == READ,
- 0, dio->pages, NULL);
- up_read(&current->mm->mmap_sem);
-
- /* Save for release..*/
- dio->sig = crystalhd_dio_locked;
- if (res < nr_pages) {
- BCMLOG_ERR("get pages failed: %d-%d\n", nr_pages, res);
- dio->page_cnt = res;
- crystalhd_unmap_dio(adp, dio);
- return BC_STS_ERROR;
- }
-
- dio->page_cnt = nr_pages;
- /* Get scatter/gather */
- crystalhd_init_sg(dio->sg, dio->page_cnt);
- crystalhd_set_sg(&dio->sg[0], dio->pages[0], 0, uaddr & ~PAGE_MASK);
- if (nr_pages > 1) {
- dio->sg[0].length = PAGE_SIZE - dio->sg[0].offset;
-
-#ifdef CONFIG_X86_64
- dio->sg[0].dma_length = dio->sg[0].length;
-#endif
- count -= dio->sg[0].length;
- for (i = 1; i < nr_pages; i++) {
- if (count < 4) {
- spsz = count;
- skip_fb_sg = 1;
- } else {
- spsz = (count < PAGE_SIZE) ?
- (count & ~0x03) : PAGE_SIZE;
- }
- crystalhd_set_sg(&dio->sg[i], dio->pages[i], spsz, 0);
- count -= spsz;
- }
- } else {
- if (count < 4) {
- dio->sg[0].length = count;
- skip_fb_sg = 1;
- } else {
- dio->sg[0].length = count - dio->fb_size;
- }
-#ifdef CONFIG_X86_64
- dio->sg[0].dma_length = dio->sg[0].length;
-#endif
- }
- dio->sg_cnt = pci_map_sg(adp->pdev, dio->sg,
- dio->page_cnt, dio->direction);
- if (dio->sg_cnt <= 0) {
- BCMLOG_ERR("sg map %d-%d\n", dio->sg_cnt, dio->page_cnt);
- crystalhd_unmap_dio(adp, dio);
- return BC_STS_ERROR;
- }
- if (dio->sg_cnt && skip_fb_sg)
- dio->sg_cnt -= 1;
- dio->sig = crystalhd_dio_sg_mapped;
- /* Fill in User info.. */
- dio->uinfo.xfr_len = ubuff_sz;
- dio->uinfo.xfr_buff = ubuff;
- dio->uinfo.uv_offset = uv_offset;
- dio->uinfo.b422mode = en_422mode;
- dio->uinfo.dir_tx = dir_tx;
-
- *dio_hnd = dio;
-
- return BC_STS_SUCCESS;
-}
-
-/**
- * crystalhd_unmap_sgl - Release mapped resources
- * @adp: Adapter instance
- * @dio: DIO request instance
- *
- * Return:
- * Status.
- *
- * This routine is to unmap the user buffer pages.
- */
-enum BC_STATUS crystalhd_unmap_dio(struct crystalhd_adp *adp,
- struct crystalhd_dio_req *dio)
-{
- struct page *page = NULL;
- int j = 0;
-
- if (!adp || !dio) {
- BCMLOG_ERR("Invalid arg\n");
- return BC_STS_INV_ARG;
- }
-
- if ((dio->page_cnt > 0) && (dio->sig != crystalhd_dio_inv)) {
- for (j = 0; j < dio->page_cnt; j++) {
- page = dio->pages[j];
- if (page) {
- if (!PageReserved(page) &&
- (dio->direction == DMA_FROM_DEVICE))
- SetPageDirty(page);
- page_cache_release(page);
- }
- }
- }
- if (dio->sig == crystalhd_dio_sg_mapped)
- pci_unmap_sg(adp->pdev, dio->sg, dio->page_cnt,
- dio->direction);
-
- crystalhd_free_dio(adp, dio);
-
- return BC_STS_SUCCESS;
-}
-
-/**
- * crystalhd_create_dio_pool - Allocate mem pool for DIO management.
- * @adp: Adapter instance
- * @max_pages: Max pages for size calculation.
- *
- * Return:
- * system error.
- *
- * This routine creates a memory pool to hold dio context for
- * for HW Direct IO operation.
- */
-int crystalhd_create_dio_pool(struct crystalhd_adp *adp, uint32_t max_pages)
-{
- uint32_t asz = 0, i = 0;
- uint8_t *temp;
- struct crystalhd_dio_req *dio;
-
- if (!adp || !max_pages) {
- BCMLOG_ERR("Invalid Arg!!\n");
- return -EINVAL;
- }
-
- /* Get dma memory for fill byte handling..*/
- adp->fill_byte_pool = pci_pool_create("crystalhd_fbyte",
- adp->pdev, 8, 8, 0);
- if (!adp->fill_byte_pool) {
- BCMLOG_ERR("failed to create fill byte pool\n");
- return -ENOMEM;
- }
-
- /* Get the max size from user based on 420/422 modes */
- asz = (sizeof(*dio->pages) * max_pages) +
- (sizeof(*dio->sg) * max_pages) + sizeof(*dio);
-
- BCMLOG(BCMLOG_DBG, "Initializing Dio pool %d %d %x %p\n",
- BC_LINK_SG_POOL_SZ, max_pages, asz, adp->fill_byte_pool);
-
- for (i = 0; i < BC_LINK_SG_POOL_SZ; i++) {
- temp = kzalloc(asz, GFP_KERNEL);
- if ((temp) == NULL) {
- BCMLOG_ERR("Failed to alloc %d mem\n", asz);
- return -ENOMEM;
- }
-
- dio = (struct crystalhd_dio_req *)temp;
- temp += sizeof(*dio);
- dio->pages = (struct page **)temp;
- temp += (sizeof(*dio->pages) * max_pages);
- dio->sg = (struct scatterlist *)temp;
- dio->max_pages = max_pages;
- dio->fb_va = pci_pool_alloc(adp->fill_byte_pool, GFP_KERNEL,
- &dio->fb_pa);
- if (!dio->fb_va) {
- BCMLOG_ERR("fill byte alloc failed.\n");
- return -ENOMEM;
- }
-
- crystalhd_free_dio(adp, dio);
- }
-
- return 0;
-}
-
-/**
- * crystalhd_destroy_dio_pool - Release DIO mem pool.
- * @adp: Adapter instance
- *
- * Return:
- * none.
- *
- * This routine releases dio memory pool during close.
- */
-void crystalhd_destroy_dio_pool(struct crystalhd_adp *adp)
-{
- struct crystalhd_dio_req *dio;
- int count = 0;
-
- if (!adp) {
- BCMLOG_ERR("Invalid Arg!!\n");
- return;
- }
-
- do {
- dio = crystalhd_alloc_dio(adp);
- if (dio) {
- if (dio->fb_va)
- pci_pool_free(adp->fill_byte_pool,
- dio->fb_va, dio->fb_pa);
- count++;
- kfree(dio);
- }
- } while (dio);
-
- if (adp->fill_byte_pool) {
- pci_pool_destroy(adp->fill_byte_pool);
- adp->fill_byte_pool = NULL;
- }
-
- BCMLOG(BCMLOG_DBG, "Released dio pool %d\n", count);
-}
-
-/**
- * crystalhd_create_elem_pool - List element pool creation.
- * @adp: Adapter instance
- * @pool_size: Number of elements in the pool.
- *
- * Return:
- * 0 - success, <0 error
- *
- * Create general purpose list element pool to hold pending,
- * and active requests.
- */
-int crystalhd_create_elem_pool(struct crystalhd_adp *adp,
- uint32_t pool_size)
-{
- uint32_t i;
- struct crystalhd_elem *temp;
-
- if (!adp || !pool_size)
- return -EINVAL;
-
- for (i = 0; i < pool_size; i++) {
- temp = kzalloc(sizeof(*temp), GFP_KERNEL);
- if (!temp) {
- BCMLOG_ERR("kalloc failed\n");
- return -ENOMEM;
- }
- crystalhd_free_elem(adp, temp);
- }
- BCMLOG(BCMLOG_DBG, "allocated %d elem\n", pool_size);
- return 0;
-}
-
-/**
- * crystalhd_delete_elem_pool - List element pool deletion.
- * @adp: Adapter instance
- *
- * Return:
- * none
- *
- * Delete general purpose list element pool.
- */
-void crystalhd_delete_elem_pool(struct crystalhd_adp *adp)
-{
- struct crystalhd_elem *temp;
- int dbg_cnt = 0;
-
- if (!adp)
- return;
-
- do {
- temp = crystalhd_alloc_elem(adp);
- if (temp) {
- kfree(temp);
- dbg_cnt++;
- }
- } while (temp);
-
- BCMLOG(BCMLOG_DBG, "released %d elem\n", dbg_cnt);
-}
-
-/*================ Debug support routines.. ================================*/
-void crystalhd_show_buffer(uint32_t off, uint8_t *buff, uint32_t dwcount)
-{
- uint32_t i, k = 1;
-
- for (i = 0; i < dwcount; i++) {
- if (k == 1)
- BCMLOG(BCMLOG_DATA, "0x%08X : ", off);
-
- BCMLOG(BCMLOG_DATA, " 0x%08X ", *((uint32_t *)buff));
-
- buff += sizeof(uint32_t);
- off += sizeof(uint32_t);
- k++;
- if ((i == dwcount - 1) || (k > 4)) {
- BCMLOG(BCMLOG_DATA, "\n");
- k = 1;
- }
- }
-}