Re: [Patch v4 2/2] dmaengine: Add ADM driver
From: Vinod Koul <hidden>
Date: 2015-03-13 09:01:52
Also in:
linux-arm-kernel, linux-arm-msm, lkml
On Wed, Feb 11, 2015 at 11:46:05PM -0600, Andy Gross wrote:
quoted hunk ↗ jump to hunk
+++ 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