Messages in this thread | | | Date | Mon, 09 Jan 2012 16:41:33 +0530 | From | Ravi Kumar V <> | Subject | Re: [PATCH v2 2/2] msm: DMAEngine: Add DMAEngine driver based on old MSM DMA APIs |
| |
On 1/7/2012 7:29 AM, Daniel Walker wrote: > On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote: >> Add DMAEngine based driver using the old MSM DMA APIs internally. >> The benefit of this approach is that not all the drivers >> have to get converted to DMAEngine APIs simultaneosly while >> both the drivers can stay enabled in the kernel. The client >> drivers using the old MSM APIs directly can now convert to >> DMAEngine one by one. >> >> Change-Id: I3647ed7b8c73b3078dfa8877a3560db3cb0a2373 >> Signed-off-by: Ravi Kumar V<kumarrav@codeaurora.org> >> --- >> arch/arm/mach-msm/include/mach/dma.h | 33 ++ >> drivers/dma/Kconfig | 12 + >> drivers/dma/Makefile | 1 + >> drivers/dma/msm-dma.c | 764 ++++++++++++++++++++++++++++++++++ >> 4 files changed, 810 insertions(+), 0 deletions(-) >> create mode 100644 drivers/dma/msm-dma.c >> >> diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h >> index 05583f5..34f4dac 100644 >> --- a/arch/arm/mach-msm/include/mach/dma.h >> +++ b/arch/arm/mach-msm/include/mach/dma.h >> @@ -18,6 +18,39 @@ >> #include<linux/list.h> >> #include<mach/msm_iomap.h> >> >> +#define msm_dma_set_crci(sg, crci) (((sg)->private_data) = \ >> + (((sg)->private_data)& ~(0x7F8)) | \ >> + crci) >> +#define msm_dma_set_endian(sg, en) (((sg)->private_data) = \ >> + (((sg)->private_data)& ~(0x1F800)) | \ >> + en) >> +#define msm_dma_set_tcb(sg, tcb) (((sg)->private_data) = \ >> + (((sg)->private_data)& ~(0x80000)) | \ >> + tcb) >> +#define sg_dma_offset(sg) ((sg)->offset) >> +#define sg_dma_private_data(sg) ((sg)->private_data) >> +#define box_dma_row_address(box) ((box)->dma_row_address) >> +#define box_dma_row_len(box) ((box)->dma_row_len) >> +#define box_dma_row_num(box) ((box)->dma_row_num) >> +#define box_dma_row_offset(box) ((box)->dma_row_offset) >> +#define box_dma_private_data(box) ((box)->private_data) >> + >> +#define MSM_DMA_CMD_MASK 0x9FFF8 >> +#define MSM_DMA_CMD_SHIFT 0 >> +#define MSM_BOX_SRC_RLEN_MASK 0xFFFF >> +#define MSM_BOX_SRC_RLEN_SHIFT 16 >> +#define MSM_BOX_SRC_RNUM_MASK 0xFFFF >> +#define MSM_BOX_SRC_RNUM_SHIFT 16 >> +#define MSM_BOX_SRC_ROFFSET_MASK 0xFFFF >> +#define MSM_BOX_SRC_ROFFSET_SHIFT 16 >> +#define MSM_BOX_DST_RLEN_MASK 0xFFFF >> +#define MSM_BOX_DST_RNUM_MASK 0xFFFF >> +#define MSM_BOX_DST_ROFFSET_MASK 0xFFFF >> +#define MSM_BOX_MODE_CMD 0x3 >> + >> +#define FORCED_FLUSH 0 >> +#define GRACEFUL_FLUSH 1 > > Could be an enum .. > >> struct msm_dmov_errdata { >> uint32_t flush[6]; >> }; >> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig >> index ab8f469..3e69f42 100644 >> --- a/drivers/dma/Kconfig >> +++ b/drivers/dma/Kconfig >> @@ -245,6 +245,18 @@ config EP93XX_DMA >> help >> Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller. >> >> +config MSM_DMA >> + tristate "Qualcomm MSM DMA support" >> + depends on ARCH_MSM >> + select DMA_ENGINE >> + help >> + Support the Qualcomm DMA engine. This engine is integrated into >> + Qualcomm chips. >> + >> + Say Y here if you have such a chipset. >> + >> + If unsure, say N. >> + >> config DMA_ENGINE >> bool >> >> diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile >> index 30cf3b1..56593f0 100644 >> --- a/drivers/dma/Makefile >> +++ b/drivers/dma/Makefile >> @@ -19,6 +19,7 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o >> obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/ >> obj-$(CONFIG_IMX_SDMA) += imx-sdma.o >> obj-$(CONFIG_IMX_DMA) += imx-dma.o >> +obj-$(CONFIG_MSM_DMA) += msm-dma.o >> obj-$(CONFIG_MXS_DMA) += mxs-dma.o >> obj-$(CONFIG_TIMB_DMA) += timb_dma.o >> obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o >> diff --git a/drivers/dma/msm-dma.c b/drivers/dma/msm-dma.c >> new file mode 100644 >> index 0000000..51d9a2b >> --- /dev/null >> +++ b/drivers/dma/msm-dma.c >> @@ -0,0 +1,764 @@ >> +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 and >> + * only version 2 as published by the Free Software Foundation. >> + * >> + * This program 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. >> + */ >> +#include<linux/init.h> >> +#include<linux/slab.h> >> +#include<linux/clk.h> >> +#include<linux/err.h> >> +#include<linux/io.h> >> +#include<linux/interrupt.h> >> +#include<linux/module.h> >> +#include<linux/platform_device.h> >> +#include<linux/spinlock.h> >> +#include<linux/dmapool.h> >> +#include<linux/dmaengine.h> >> +#include<linux/dma-mapping.h> >> + >> +#include<mach/dma.h> >> + >> +#define SD3_CHAN_START 0 >> +#define MSM_DMOV_CRCI_COUNT 16 >> +#define MSM_DMA_MAX_CHANS_PER_DEVICE 16 >> +#define MAX_TRANSFER_LENGTH 65535 >> +#define NO_ERR_CHAN_STATUS 0x80000002 >> +#define to_msm_chan(chan) container_of(chan, struct msm_dma_chan, channel) >> + >> +struct msm_dma_chan { >> + int chan_id; >> + dma_cookie_t completed_cookie; >> + dma_cookie_t error_cookie; >> + spinlock_t lock; >> + struct list_head active_list; >> + struct list_head pending_list; >> + struct dma_chan channel; >> + struct dma_pool *desc_pool; >> + struct device *dev; >> + int max_len; >> + int err; >> + struct tasklet_struct tasklet; >> +}; >> + >> +struct msm_dma_device { >> + void __iomem *base; >> + struct device *dev; >> + struct dma_device common; >> + struct msm_dma_chan *chan[MSM_DMA_MAX_CHANS_PER_DEVICE]; >> +}; >> + >> +struct msm_dma_desc_hw { >> + unsigned int cmd_list_ptr; >> +} __aligned(8); >> + >> +/* Single Item Mode */ >> +struct adm_cmd_t { >> + unsigned int cmd_cntrl; >> + unsigned int src; >> + unsigned int dst; >> + unsigned int len; >> +}; >> + >> +struct adm_box_cmd_t { >> + uint32_t cmd_cntrl; >> + uint32_t src_row_addr; >> + uint32_t dst_row_addr; >> + uint32_t src_dst_len; >> + uint32_t num_rows; >> + uint32_t row_offset; >> +}; >> + >> +struct msm_dma_desc_sw { >> + struct msm_dma_desc_hw hw; >> + struct adm_cmd_t *vaddr_cmd; >> + struct adm_box_cmd_t *vaddr_box_cmd; >> + size_t coherent_size; >> + dma_addr_t paddr_cmd_list; >> + struct list_head node; >> + struct msm_dmov_cmd dmov_cmd; >> + struct dma_async_tx_descriptor async_tx; >> +} __aligned(8); >> + >> +static int msm_dma_alloc_chan_resources(struct dma_chan *dchan) >> +{ >> + struct msm_dma_chan *chan = to_msm_chan(dchan); >> + >> + /* Has this channel already been allocated? */ >> + if (chan->desc_pool) >> + return 1; >> + >> + /* >> + * We need the descriptor to be aligned to 8bytes >> + * for meeting ADM specification requirement. >> + */ >> + chan->desc_pool = dma_pool_create("msm_dma_desc_pool", >> + chan->dev, >> + sizeof(struct msm_dma_desc_sw), >> + __alignof__(struct msm_dma_desc_sw), 0); >> + if (!chan->desc_pool) { >> + dev_err(chan->dev, "unable to allocate channel %d " >> + "descriptor pool\n", chan->chan_id); >> + return -ENOMEM; >> + } >> + >> + chan->completed_cookie = 1; >> + dchan->cookie = 1; >> + >> + /* there is at least one descriptor free to be allocated */ >> + return 1; >> +} >> + >> +static void msm_dma_free_desc_list(struct msm_dma_chan *chan, >> + struct list_head *list) >> +{ >> + struct msm_dma_desc_sw *desc, *_desc; >> + >> + list_for_each_entry_safe(desc, _desc, list, node) { >> + list_del(&desc->node); >> + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); >> + } >> +} >> + >> +static void msm_dma_free_chan_resources(struct dma_chan *dchan) >> +{ >> + struct msm_dma_chan *chan = to_msm_chan(dchan); >> + unsigned long flags; >> + >> + dev_dbg(chan->dev, "Free all channel resources.\n"); >> + spin_lock_irqsave(&chan->lock, flags); >> + msm_dma_free_desc_list(chan,&chan->active_list); >> + msm_dma_free_desc_list(chan,&chan->pending_list); >> + spin_unlock_irqrestore(&chan->lock, flags); >> + >> + dma_pool_destroy(chan->desc_pool); >> + chan->desc_pool = NULL; >> +} >> + >> +static enum dma_status msm_dma_desc_status(struct msm_dma_chan *chan, >> + struct msm_dma_desc_sw *desc) >> +{ >> + return dma_async_is_complete(desc->async_tx.cookie, >> + chan->completed_cookie, >> + chan->channel.cookie); >> +} >> + >> +static void msm_chan_desc_cleanup(struct msm_dma_chan *chan) >> +{ >> + struct msm_dma_desc_sw *desc, *_desc; >> + unsigned long flags; >> + >> + dev_dbg(chan->dev, "Cleaning completed descriptor of channel %d\n", >> + chan->chan_id); >> + spin_lock_irqsave(&chan->lock, flags); >> + >> + list_for_each_entry_safe(desc, _desc,&chan->active_list, node) { >> + dma_async_tx_callback callback; >> + void *callback_param; >> + >> + if (msm_dma_desc_status(chan, desc) == DMA_IN_PROGRESS) >> + break; >> + >> + /* Remove from the list of running transactions */ >> + list_del(&desc->node); >> + >> + /* Run the link descriptor callback function */ >> + callback = desc->async_tx.callback; >> + callback_param = desc->async_tx.callback_param; >> + if (callback) { >> + spin_unlock_irqrestore(&chan->lock, flags); >> + callback(callback_param); > > Are you sure unlocking here is safe? at_hdmac.c holds the lock the > entire time, and fsldma.c deletes the entire list, then runs the > operations. > >> + spin_lock_irqsave(&chan->lock, flags); >> + } >> + >> + /* Run any dependencies, then free the descriptor */ >> + dma_run_dependencies(&desc->async_tx); >> + spin_unlock_irqrestore(&chan->lock, flags); >> + >> + if (desc->vaddr_cmd) { >> + dma_free_coherent(chan->dev, desc->coherent_size, >> + (void *)desc->vaddr_cmd, >> + desc->paddr_cmd_list); >> + } else { >> + dma_free_coherent(chan->dev, desc->coherent_size, >> + (void *)desc->vaddr_box_cmd, >> + desc->paddr_cmd_list); >> + } >> + spin_lock_irqsave(&chan->lock, flags); >> + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); >> + } >> + >> + spin_unlock_irqrestore(&chan->lock, flags); >> +} >> + >> +static void dma_do_tasklet(unsigned long data) >> +{ >> + struct msm_dma_chan *chan = (struct msm_dma_chan *)data; >> + msm_chan_desc_cleanup(chan); >> +} >> + >> +static void >> +msm_dma_complete_func(struct msm_dmov_cmd *cmd, >> + unsigned int result, >> + struct msm_dmov_errdata *err) >> +{ >> + unsigned long flags; >> + struct msm_dma_desc_sw *desch = container_of(cmd, >> + struct msm_dma_desc_sw, dmov_cmd); >> + struct msm_dma_chan *chan = to_msm_chan(desch->async_tx.chan); >> + >> + spin_lock_irqsave(&chan->lock, flags); >> + >> + if ((result != NO_ERR_CHAN_STATUS)&& err) >> + chan->error_cookie = desch->async_tx.cookie; >> + chan->completed_cookie = desch->async_tx.cookie; >> + >> + tasklet_schedule(&chan->tasklet); >> + >> + spin_unlock_irqrestore(&chan->lock, flags); >> +} >> + >> +/* >> + * Passes transfer descriptors to DMA hardware. >> + */ >> +static void msm_dma_issue_pending(struct dma_chan *dchan) >> +{ >> + struct msm_dma_chan *chan = to_msm_chan(dchan); >> + struct msm_dma_desc_sw *desch; >> + unsigned long flags; >> + >> + if (chan->err) >> + return; >> + >> + spin_lock_irqsave(&chan->lock, flags); >> + >> + if (list_empty(&chan->pending_list)) >> + goto out_unlock; >> + >> + desch = list_first_entry(&chan->pending_list, struct msm_dma_desc_sw, >> + node); >> + list_del(&desch->node); >> + desch->dmov_cmd.complete_func = msm_dma_complete_func; >> + desch->dmov_cmd.execute_func = NULL; >> + desch->dmov_cmd.cmdptr = DMOV_CMD_ADDR(desch->async_tx.phys); >> + list_add_tail(&desch->node,&chan->active_list); >> + mb(); >> + msm_dmov_enqueue_cmd(chan->chan_id,&desch->dmov_cmd); >> +out_unlock: >> + spin_unlock_irqrestore(&chan->lock, flags); >> +} >> + >> +/* >> + * Assignes cookie for each transfer descriptor passed. >> + * Returns >> + * Assigend cookie for success. >> + * Error value for failure. >> + */ >> +static dma_cookie_t msm_dma_tx_submit(struct dma_async_tx_descriptor *tx) >> +{ >> + struct msm_dma_chan *chan = to_msm_chan(tx->chan); >> + struct msm_dma_desc_sw *desc = container_of(tx, >> + struct msm_dma_desc_sw, async_tx); >> + unsigned long flags; >> + dma_cookie_t cookie = -EBUSY; >> + >> + if (chan->err) >> + return cookie; >> + >> + spin_lock_irqsave(&chan->lock, flags); >> + >> + /* >> + * assign cookies to all of the software descriptors >> + * that make up this transaction >> + */ >> + cookie = chan->channel.cookie; >> + cookie++; >> + if (cookie< 0) >> + cookie = DMA_MIN_COOKIE; >> + >> + desc->async_tx.cookie = cookie; >> + chan->channel.cookie = cookie; >> + >> + /* put this transaction onto the tail of the pending queue */ >> + list_add_tail(&desc->node,&chan->pending_list); >> + >> + spin_unlock_irqrestore(&chan->lock, flags); >> + >> + return cookie; >> +} >> + >> +/* >> + * Returns the DMA transfer status of a particular cookie >> + */ >> +static enum dma_status msm_tx_status(struct dma_chan *dchan, >> + dma_cookie_t cookie, >> + struct dma_tx_state *txstate) >> +{ >> + struct msm_dma_chan *chan = to_msm_chan(dchan); >> + dma_cookie_t last_used; >> + dma_cookie_t last_complete; >> + enum dma_status status; >> + >> + last_used = dchan->cookie; >> + last_complete = chan->completed_cookie; >> + >> + dma_set_tx_state(txstate, last_complete, last_used, 0); >> + >> + status = dma_async_is_complete(cookie, last_complete, last_used); >> + >> + if (status != DMA_IN_PROGRESS) >> + if (chan->error_cookie == cookie) >> + status = DMA_ERROR; >> + >> + return status; >> +} >> + >> +static struct msm_dma_desc_sw *msm_dma_alloc_descriptor( >> + struct msm_dma_chan *chan, >> + int cmd_cnt, >> + int mask) >> +{ >> + struct msm_dma_desc_sw *desc; >> + dma_addr_t pdesc_addr; >> + dma_addr_t paddr_cmd_list; >> + void *err = NULL; >> + >> + desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC,&pdesc_addr); >> + if (!desc) { >> + dev_dbg(chan->dev, "out of memory for desc\n"); >> + return ERR_CAST(desc); >> + } >> + >> + memset(desc, 0, sizeof(*desc)); >> + desc->async_tx.phys = pdesc_addr; >> + >> + if (mask == DMA_BOX) { >> + desc->coherent_size = sizeof(struct adm_box_cmd_t); >> + desc->vaddr_box_cmd = dma_alloc_coherent(chan->dev, >> + sizeof(struct adm_box_cmd_t), >> + &paddr_cmd_list, GFP_ATOMIC); >> + if (!desc->vaddr_box_cmd) { >> + dev_dbg(chan->dev, "out of memory for desc\n"); >> + err = desc->vaddr_box_cmd; >> + goto fail; >> + } >> + } else { >> + desc->coherent_size = sizeof(struct adm_cmd_t)*cmd_cnt; >> + >> + desc->vaddr_cmd = dma_alloc_coherent(chan->dev, >> + sizeof(struct adm_cmd_t)*cmd_cnt, >> + &paddr_cmd_list, GFP_ATOMIC); >> + >> + if (!desc->vaddr_cmd) { >> + dev_dbg(chan->dev, "out of memory for desc\n"); >> + err = desc->vaddr_cmd; >> + goto fail; >> + } >> + } >> + >> + dma_async_tx_descriptor_init(&desc->async_tx,&chan->channel); >> + desc->async_tx.tx_submit = msm_dma_tx_submit; >> + desc->paddr_cmd_list = paddr_cmd_list; >> + desc->hw.cmd_list_ptr = (paddr_cmd_list>> 3) | CMD_PTR_LP; >> + return desc; >> +fail: >> + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); >> + return ERR_CAST(err); >> +} >> + >> +/* >> + * Prepares the transfer descriptors for SG transaction. >> + * Returns >> + * address of dma_async_tx_descriptor for success. >> + * Pointer of error value for failure. >> + */ >> +static struct dma_async_tx_descriptor *msm_dma_prep_sg( >> + struct dma_chan *dchan, >> + struct scatterlist *dst_sg, unsigned int dst_nents, >> + struct scatterlist *src_sg, unsigned int src_nents, >> + unsigned long flags) >> +{ >> + >> + struct msm_dma_chan *chan; >> + struct msm_dma_desc_sw *new; >> + size_t copy, len; >> + int cmd_cnt = 0; >> + int first = 0; >> + int i; >> + dma_addr_t src; >> + dma_addr_t dst; >> + struct adm_cmd_t *cmdlist_vaddr; >> + struct scatterlist *sg; >> + >> + if (!dchan) >> + return ERR_PTR(-EINVAL); >> + >> + if (dst_nents == 0 || src_nents == 0) >> + return ERR_PTR(-EINVAL); >> + if (!dst_sg || !src_sg) >> + return ERR_PTR(-EINVAL); >> + >> + if (dst_nents != src_nents) >> + return ERR_PTR(-EINVAL); >> + >> + chan = to_msm_chan(dchan); >> + >> + cmd_cnt = src_nents; >> + >> + for (i = 0; i< src_nents; i++) { >> + len = sg_dma_len(src_sg + i); >> + if (len != MAX_TRANSFER_LENGTH) >> + cmd_cnt += len/MAX_TRANSFER_LENGTH; >> + } >> + >> + new = msm_dma_alloc_descriptor(chan, cmd_cnt, DMA_SG); >> + >> + if (!new) { >> + dev_err(chan->dev, >> + "No free memory for link descriptor\n"); >> + return ERR_PTR(-ENOMEM); >> + } >> + >> + cmdlist_vaddr = new->vaddr_cmd; >> + >> + for_each_sg(src_sg, sg, src_nents, i) { >> + len = sg_dma_len(sg); >> + src = sg_dma_address(sg); >> + do { >> + copy = (len>= MAX_TRANSFER_LENGTH) ? >> + MAX_TRANSFER_LENGTH : len; >> + cmdlist_vaddr->src = src; >> + cmdlist_vaddr->len = copy; >> + cmdlist_vaddr->cmd_cntrl = >> + (sg_dma_private_data(sg)& MSM_DMA_CMD_MASK); >> + if (first == 0) { >> + if (cmd_cnt == 1) >> + cmdlist_vaddr->cmd_cntrl = CMD_LC | >> + CMD_OCB | CMD_OCU; >> + else >> + cmdlist_vaddr->cmd_cntrl = CMD_OCB; >> + first = 1; >> + } >> + cmdlist_vaddr++; >> + len -= copy; >> + src += copy; >> + } while (len); >> + } >> + if (cmd_cnt> 1) { >> + cmdlist_vaddr--; >> + cmdlist_vaddr->cmd_cntrl |= CMD_LC | CMD_OCU; >> + } >> + >> + cmdlist_vaddr = new->vaddr_cmd; >> + >> + for_each_sg(dst_sg, sg, src_nents, i) { >> + len = sg_dma_len(sg); >> + dst = sg_dma_address(sg); >> + do { >> + copy = (len>= MAX_TRANSFER_LENGTH) ? >> + MAX_TRANSFER_LENGTH : len; >> + cmdlist_vaddr->dst = dst; >> + cmdlist_vaddr++; >> + len -= copy; >> + dst += copy; >> + } while (len); >> + >> + } >> + >> +#ifdef DEBUG >> + cmdlist_vaddr = new->vaddr_cmd; >> + i = 0; >> + do { >> + dev_dbg(chan->dev, "cmd %d src 0x%x dst 0x%x len 0x%x " >> + "cntrl 0x%x\n", >> + i, cmdlist_vaddr->src, cmdlist_vaddr->dst, > > Doesn't look like "i" has a log of meaning here. > > If it were me I'd make the two #ifdef DEBUG blocks into helper > functions, then you could combine them into a single block. Would look > cleaner too I think. > >> + cmdlist_vaddr->len, cmdlist_vaddr->cmd_cntrl); >> + cmdlist_vaddr++; >> + } while (!((cmdlist_vaddr-1)->cmd_cntrl& CMD_LC)); >> +#endif > >> + new->async_tx.flags = flags; >> + new->async_tx.cookie = -EBUSY; >> + >> + return&new->async_tx; >> +} >> + >> +/* >> + * Prepares the transfer descriptors for BOX transaction. >> + * Returns >> + * address of dma_async_tx_descriptor for success. >> + * Pointer of error value for failure. >> + */ >> +static struct dma_async_tx_descriptor *msm_dma_prep_box( >> + struct dma_chan *dchan, >> + struct dma_box_list *dst_box, struct dma_box_list *src_box, >> + unsigned int num_list, unsigned long flags) >> +{ >> + struct msm_dma_chan *chan; >> + struct msm_dma_desc_sw *new; >> + int cmd_cnt = 0; >> + int first = 0; >> + int i; >> + struct adm_box_cmd_t *box_cmd_vaddr; >> + >> + if (!dchan) >> + return ERR_PTR(-EINVAL); >> + >> + if (num_list == 0) >> + return ERR_PTR(-EINVAL); >> + if (!dst_box || !src_box) >> + return ERR_PTR(-EINVAL); >> + >> + chan = to_msm_chan(dchan); >> + >> + cmd_cnt = num_list; >> + >> + new = msm_dma_alloc_descriptor(chan, cmd_cnt, DMA_BOX); >> + >> + if (!new) { >> + dev_err(chan->dev, >> + "No free memory for link descriptor\n"); >> + return ERR_PTR(-ENOMEM); >> + } >> + box_cmd_vaddr = new->vaddr_box_cmd; >> + >> + for (i = 0; i< num_list; i++) { >> + >> + box_cmd_vaddr->src_row_addr = >> + box_dma_row_address(src_box + i); >> + box_cmd_vaddr->src_dst_len = >> + (box_dma_row_len(src_box + i)& >> + MSM_BOX_SRC_RLEN_MASK)<< >> + MSM_BOX_SRC_RLEN_SHIFT; >> + box_cmd_vaddr->cmd_cntrl = >> + (box_dma_private_data(src_box + i)& >> + MSM_DMA_CMD_MASK) | MSM_BOX_MODE_CMD; >> + >> + box_cmd_vaddr->num_rows = (box_dma_row_num(src_box + i)& >> + MSM_BOX_SRC_RNUM_MASK)<< >> + MSM_BOX_SRC_RNUM_SHIFT; >> + >> + box_cmd_vaddr->row_offset = (box_dma_row_offset(src_box + i)& >> + MSM_BOX_SRC_ROFFSET_MASK)<< >> + MSM_BOX_SRC_ROFFSET_SHIFT; >> + >> + if (first == 0) { >> + if (cmd_cnt == 1) >> + box_cmd_vaddr->cmd_cntrl |= >> + CMD_LC | CMD_OCB | CMD_OCU; >> + else >> + box_cmd_vaddr->cmd_cntrl |= >> + CMD_OCB; >> + first = 1; >> + } >> + box_cmd_vaddr++; >> + } >> + >> + if (cmd_cnt> 1) { >> + box_cmd_vaddr--; >> + box_cmd_vaddr->cmd_cntrl |= CMD_LC | CMD_OCU; >> + } >> + >> + box_cmd_vaddr = new->vaddr_box_cmd; >> + >> + for (i = 0; i< num_list; i++) { >> + >> + box_cmd_vaddr->dst_row_addr = box_dma_row_address(dst_box + i); >> + box_cmd_vaddr->src_dst_len |= >> + (box_dma_row_len(dst_box + i)& MSM_BOX_DST_RLEN_MASK); >> + box_cmd_vaddr->num_rows |= >> + (box_dma_row_num(dst_box + i)& >> + MSM_BOX_DST_RNUM_MASK); >> + >> + box_cmd_vaddr->row_offset |= >> + (box_dma_row_offset(dst_box + i)& >> + MSM_BOX_DST_ROFFSET_MASK); >> + box_cmd_vaddr++; >> + } >> +#ifdef DEBUG >> + i = 0; >> + box_cmd_vaddr = new->vaddr_box_cmd; >> + do { >> + dev_dbg(chan->dev, "cmd %d src 0x%x dst 0x%x len 0x%x " >> + "cntrl 0x%x row_offset 0x%x num_rows 0x%x\n", >> + i, box_cmd_vaddr->src_row_addr, >> + box_cmd_vaddr->dst_row_addr, >> + box_cmd_vaddr->src_dst_len, >> + box_cmd_vaddr->cmd_cntrl, >> + box_cmd_vaddr->row_offset, >> + box_cmd_vaddr->num_rows); >> + box_cmd_vaddr++; >> + i++; >> + } while (!((box_cmd_vaddr-1)->cmd_cntrl& CMD_LC)); >> +#endif >> + new->async_tx.flags = flags; >> + new->async_tx.cookie = -EBUSY; >> + >> + return&new->async_tx; >> +} >> + >> +/* >> + * Controlling the hardware channel like stopping, flushing. >> + */ >> +static int msm_dma_chan_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, >> + unsigned long arg) >> +{ >> + int cmd_type = (int) arg; > > Why do you need to cast here? Both the flush macro's are positive. > >> + >> + if (cmd == DMA_TERMINATE_ALL) { >> + switch (cmd_type) { >> + case GRACEFUL_FLUSH: >> + msm_dmov_stop_cmd(chan->chan_id, NULL, 1); >> + break; >> + case FORCED_FLUSH: >> + /* >> + * We treate default as forced flush >> + * so we fall through >> + */ >> + default: >> + msm_dmov_stop_cmd(chan->chan_id, NULL, 0); >> + break; >> + } >> + } >> + return 0; >> +} >> + > >
I will address the comments in next patch release, i will wait for sometime for vinod comments and release new patch v3.
Ravi -- Sent by a consultant of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
| |