On Wed, Feb 11, 2015 at 11:46:05PM -0600, Andy Gross wrote: > +++ b/drivers/dma/qcom_adm.c > @@ -0,0 +1,901 @@ > +/* > + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. shouldn't this be 15 :) +/* ADM registers - calculated from channel number and security domain */ > +#define HI_CH_CMD_PTR(chan, ee) (4*chan + 0x20800*ee) > +#define HI_CH_RSLT(chan, ee) (0x40 + 4*chan + 0x20800*ee) > +#define HI_CH_FLUSH_STATE0(chan, ee) (0x80 + 4*chan + 0x20800*ee) > +#define HI_CH_FLUSH_STATE1(chan, ee) (0xc0 + 4*chan + 0x20800*ee) > +#define HI_CH_FLUSH_STATE2(chan, ee) (0x100 + 4*chan + 0x20800*ee) > +#define HI_CH_FLUSH_STATE3(chan, ee) (0x140 + 4*chan + 0x20800*ee) > +#define HI_CH_FLUSH_STATE4(chan, ee) (0x180 + 4*chan + 0x20800*ee) > +#define HI_CH_FLUSH_STATE5(chan, ee) (0x1c0 + 4*chan + 0x20800*ee) > +#define HI_CH_STATUS_SD(chan, ee) (0x200 + 4*chan + 0x20800*ee) > +#define HI_CH_CONF(chan) (0x240 + 4*chan) > +#define HI_CH_RSLT_CONF(chan, ee) (0x300 + 4*chan + 0x20800*ee) > +#define HI_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + 0x20800*ee) > +#define HI_CI_CONF(ci) (0x390 + 4*ci) > +#define HI_CRCI_CONF0 0x3d0 > +#define HI_CRCI_CONF1 0x3d4 > +#define HI_GP_CTL 0x3d8 > +#define HI_CRCI_CTL(crci, ee) (0x400 + 0x4*crci + 0x20800*ee) two things, one the names are quite generic and may cause conflicts so pls fix that. Second the values, what is the deal with 4*chan, should that be a define as well. Also rather than copy pasting a macros would be better for this expansion > + > +/* channel status */ > +#define CH_STATUS_VALID BIT(1) > + > +/* channel result */ > +#define CH_RSLT_VALID BIT(31) > +#define CH_RSLT_ERR BIT(3) > +#define CH_RSLT_FLUSH BIT(2) > +#define CH_RSLT_TPD BIT(1) > + > +/* channel conf */ > +#define CH_CONF_MPU_DISABLE BIT(11) > +#define CH_CONF_PERM_MPU_CONF BIT(9) > +#define CH_CONF_FLUSH_RSLT_EN BIT(8) > +#define CH_CONF_FORCE_RSLT_EN BIT(7) > +#define CH_CONF_IRQ_EN BIT(6) > + > +/* channel result conf */ > +#define CH_RSLT_CONF_FLUSH_EN BIT(1) > +#define CH_RSLT_CONF_IRQ_EN BIT(0) > + > +/* CRCI CTL */ > +#define CRCI_CTL_MUX_SEL BIT(18) > +#define CRCI_CTL_RST BIT(17) > + > +/* CI configuration */ > +#define CI_RANGE_END(x) (x << 24) > +#define CI_RANGE_START(x) (x << 16) > +#define CI_BURST_4_WORDS 0x4 > +#define CI_BURST_8_WORDS 0x8 shouldn't you be consistent is usage of BIT() > + > +/* GP CTL */ > +#define GP_CTL_LP_EN BIT(12) > +#define GP_CTL_LP_CNT(x) (x << 8) > + > +/* Command pointer list entry */ > +#define CPLE_LP BIT(31) > +#define CPLE_CMD_PTR_LIST BIT(29) > + > +/* Command list entry */ > +#define CMD_LC BIT(31) > +#define CMD_DST_CRCI(n) (((n) & 0xf) << 7) > +#define CMD_SRC_CRCI(n) (((n) & 0xf) << 3) > + > +#define CMD_TYPE_SINGLE 0x0 > +#define CMD_TYPE_BOX 0x3a naming issues... > +static int adm_alloc_chan(struct dma_chan *chan) > +{ > + return 0; > +} This is no longer mandatory, so can be dropped > +static int adm_get_blksize(unsigned int burst) > +{ > + int ret; > + > + switch (burst) { > + case 16: > + ret = 0; > + break; > + case 32: > + ret = 1; > + break; > + case 64: > + ret = 2; > + break; > + case 128: > + ret = 3; > + break; > + case 192: > + ret = 4; > + break; > + case 256: > + ret = 5; > + break; ffs(burst>>4) ? > +static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, > + struct scatterlist *sgl, unsigned int sg_len, > + enum dma_transfer_direction direction, unsigned long flags, > + void *context) > +{ > + struct adm_chan *achan = to_adm_chan(chan); > + struct adm_device *adev = achan->adev; > + struct adm_async_desc *async_desc; > + struct scatterlist *sg; > + u32 i; > + u32 single_count = 0, box_count = 0, desc_offset = 0, crci = 0; > + struct adm_desc_hw_box *box_desc; > + struct adm_desc_hw_single *single_desc; > + void *desc; > + u32 *cple, *last_cmd; > + u32 burst; > + int blk_size = 0; > + > + > + if (!is_slave_direction(direction)) { > + dev_err(adev->dev, "invalid dma direction\n"); > + return NULL; > + } > + > + /* > + * get burst value from slave configuration > + * If zero, default to maximum burst size > + * If larger than the max transfer size, set to ADM_MAX_XFER > + */ > + burst = (direction == DMA_MEM_TO_DEV) ? > + achan->slave.dst_maxburst : > + achan->slave.src_maxburst; > + > + if (!burst || burst > ADM_MAX_XFER) > + burst = ADM_MAX_XFER; For slave, we should send error here. The DMA settings are matched with slave FIFO, so any change here can cause issues > + > + /* if using flow control, validate burst and crci values */ > + if (achan->slave.device_fc) { > + > + blk_size = adm_get_blksize(burst); > + if (blk_size < 0) { > + dev_err(adev->dev, "invalid burst value w/ crci: %d\n", > + burst); > + return ERR_PTR(-EINVAL); > + } > + > + crci = achan->slave.slave_id & 0xf; > + if (!crci || achan->slave.slave_id > 0x1f) { > + dev_err(adev->dev, "invalid crci value\n"); > + return ERR_PTR(-EINVAL); > + } > + } > + > + /* iterate through sgs and compute allocation size of structures */ > + for_each_sg(sgl, sg, sg_len, i) > + if (sg_dma_len(sg) % burst) > + single_count += DIV_ROUND_UP(sg_dma_len(sg), burst); > + else > + box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst, > + ADM_MAX_ROWS); > + > + async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); > + if (!async_desc) > + return ERR_PTR(-ENOMEM); > + > + if (crci) > + async_desc->mux = achan->slave.slave_id >> 4 ? > + CRCI_CTL_MUX_SEL : 0; > + async_desc->crci = crci; > + async_desc->blk_size = blk_size; > + async_desc->dma_len = single_count * sizeof(*single_desc) + > + box_count * sizeof(*box_desc) + sizeof(*cple) + > + 2*ADM_DESC_ALIGN; > + > + async_desc->cpl = dma_alloc_writecombine(adev->dev, async_desc->dma_len, > + &async_desc->dma_addr, GFP_NOWAIT); > + > + if (!async_desc->cpl) { > + kfree(async_desc); > + return ERR_PTR(-ENOMEM); > + } > + > + async_desc->adev = adev; > + > + /* both command list entry and descriptors must be 8 byte aligned */ > + cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN); > + desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN); > + last_cmd = desc; > + > + /* init cmd list */ > + *cple = CPLE_LP; > + *cple |= (desc - async_desc->cpl + async_desc->dma_addr) >> 3; > + > + for_each_sg(sgl, sg, sg_len, i) { > + unsigned int xfer_len, row_len, rows; > + unsigned int remainder = sg_dma_len(sg); > + unsigned int offset = 0; > + > + do { > + /* use single if length is not multiple of burst */ > + if (remainder % burst) { > + single_desc = desc + desc_offset; > + last_cmd = &single_desc->cmd; > + single_desc->cmd = CMD_TYPE_SINGLE; > + xfer_len = (remainder > ADM_MAX_XFER) ? > + ADM_MAX_XFER : remainder; > + if (direction == DMA_DEV_TO_MEM) { > + single_desc->dst_addr = > + sg_dma_address(sg) + offset; > + single_desc->src_addr = > + achan->slave.src_addr; > + single_desc->len = xfer_len; > + single_desc->cmd |= CMD_SRC_CRCI(crci); > + } else { > + single_desc->src_addr = > + sg_dma_address(sg) + offset; > + single_desc->dst_addr = > + achan->slave.dst_addr; > + single_desc->len = xfer_len; > + single_desc->cmd |= CMD_DST_CRCI(crci); > + } > + > + remainder -= xfer_len; > + async_desc->length += xfer_len; > + offset += xfer_len; > + desc_offset += sizeof(*single_desc); > + } else { > + box_desc = desc + desc_offset; > + last_cmd = &box_desc->cmd; > + box_desc->cmd = CMD_TYPE_BOX; > + box_desc->row_offset = 0; > + > + if (direction == DMA_DEV_TO_MEM) { > + box_desc->dst_addr = > + sg_dma_address(sg) + offset; > + box_desc->src_addr = > + achan->slave.src_addr; > + box_desc->cmd |= CMD_SRC_CRCI(crci); > + box_desc->row_offset = burst; > + > + } else { > + box_desc->src_addr = > + sg_dma_address(sg) + offset; > + box_desc->dst_addr = > + achan->slave.dst_addr; > + box_desc->cmd |= CMD_DST_CRCI(crci); > + box_desc->row_offset = burst << 16; > + } till this both look quite similar, also you are way deeply nested. I would split this up to make it look better as well try reusing common parts for both here > +static int adm_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, > + unsigned long arg) > +{ this is removed, so you need to rebase this Thanks -- ~Vinod -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html