Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp1555023imm; Wed, 8 Aug 2018 20:33:50 -0700 (PDT) X-Google-Smtp-Source: AA+uWPx6SSZoH6lJ/9AUkoIoSUf27JBrGTTxrzMiAINH5xFnAoP4Kwb4cSm2wmU5NTleIpvNlQsS X-Received: by 2002:a63:1c5f:: with SMTP id c31-v6mr386078pgm.321.1533785630668; Wed, 08 Aug 2018 20:33:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1533785630; cv=none; d=google.com; s=arc-20160816; b=aBucaoC2qAXiY8YpaoEwZt6hN9JulvH/If3cXAE4J/CwwUve1S+IxJXb1j9tvJY2y0 W47BpnHV2abr+UPdZ+pym45/aVjA+NtaavaxFyMXmrHsQ5Dynu5eP1vCndz9ILzfngtJ 1K0Rz8oYmsNDY+zxmVV/bHigiJyv6sVM1eJOGUEqqILEIRgQhpDcJsTdcR7I2mQvPIxh AfoA7QM8yQ+qGUfmw9CysUDShydoXwrcCdUBfJpXlYWCi5CxsW9NMQnscBoqEJavIkY6 PPPdBvB22AwNLlgCaadWFK8To9x+KTKcJfzXcTfmNdPjK0Z9M7ctg0NXvnh9RPDDhyG1 ZnXg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature :arc-authentication-results; bh=zWwyWUGto++RYf4LOKf3EMvTZa18AnADT4Odf69v8Aw=; b=YLJ/IMlJ8xRcQdDF24Isg1BR8jmI8BS+iHbt3wSnHd486nzwF82TFJwTBxt5JsaEA7 0yOyFPVn8LqWMXO/3NZhLzlJzgi95mTokgt47fJWsh+fftK//yZZMXXaUbrbIT4yTK7b KYeoIdWOJdM+l19Gc4kLFmZ8ILcGGUJld/9AVBoVXRe6y6qt4CrFdvMtJbvqhgUmuMTZ 8A+UwTHxARzGmT5eWiKgiis6N0l1BwLAp9+vgMdb3+MDLDfUFpo5Ccej8IzjJ4BY5zIO kQtHB6USLUQAWsnQp6Mdm6iFpkwflEhW5g0d1GFX09/9fc9V17mDGg2H3rBz5ZH93rIf E05A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YEuoSs9q; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 192-v6si6721792pfa.81.2018.08.08.20.33.35; Wed, 08 Aug 2018 20:33:50 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YEuoSs9q; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727942AbeHIFz1 (ORCPT + 99 others); Thu, 9 Aug 2018 01:55:27 -0400 Received: from mail-oi0-f65.google.com ([209.85.218.65]:33350 "EHLO mail-oi0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727237AbeHIFz1 (ORCPT ); Thu, 9 Aug 2018 01:55:27 -0400 Received: by mail-oi0-f65.google.com with SMTP id 8-v6so7538880oip.0 for ; Wed, 08 Aug 2018 20:32:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=zWwyWUGto++RYf4LOKf3EMvTZa18AnADT4Odf69v8Aw=; b=YEuoSs9q1gWd/TII+7QNrHT8nJ5lrmGagr4aLIexkkW9JdHB9YQvu6nu1RAwZosERL 2dSxmR85uFQ8UsVXWI/VpeGRSssn+3mkN5mX6g+0CrR1ZXyQr4P5n8RwTHo+mb827kPB dYL74oCyJc90dBisc3E9dd0aSXwTYDF87VXGc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=zWwyWUGto++RYf4LOKf3EMvTZa18AnADT4Odf69v8Aw=; b=SfyygBeg9RsbtKXCe9QbvK5NBTxxafO2Y1BrtMOxEyrcXu+3INZto5Av7bdU1SPq8p xwRpScpUMNYDxotYffqwQhz1PdPBeTO7V2AREiFhfUDfQCUrOcty0uXczbKFcc4Aer+x geIE8cUaDJvvS//8hKykgdHU/6KyP9z+UIwGPEf+Xukbjg+Q++MDhQ0HOrzxb2FVGSHx urve4QDUKeD47dAR95wuogX7Nz5HYPEzffqQDEgP/++jQatrPKT5M9+WtjMlr62xPjxi rD3ZPhP0euQyuwCuGZY7BpXBBHkt9eigjSDZcJS+fMTiM2l06HCjoapTno539OyzYC1V Eqgg== X-Gm-Message-State: AOUpUlEgx6ZZSaPojxVnYv4YmAA7e9rsix/ZnB0vPfm1GsKo/FNACsGv itTrypGnAhtOpqcHpgnnht1+sFR4VuewENXcxUh1XA== X-Received: by 2002:aca:dd07:: with SMTP id u7-v6mr357505oig.177.1533785566566; Wed, 08 Aug 2018 20:32:46 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a9d:237a:0:0:0:0:0 with HTTP; Wed, 8 Aug 2018 20:32:46 -0700 (PDT) In-Reply-To: <20180809023215.GO2395@vkoul-mobl> References: <78730daa2eaa66fa8089f196a52b51ce62579d1f.1532591566.git.baolin.wang@linaro.org> <20180809023215.GO2395@vkoul-mobl> From: Baolin Wang Date: Thu, 9 Aug 2018 11:32:46 +0800 Message-ID: Subject: Re: [PATCH] dmaengine: sprd: Support DMA link-list mode To: Vinod Cc: Dan Williams , Eric Long , Mark Brown , dmaengine@vger.kernel.org, LKML Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Vinod, (Comments from Eric Long) On 9 August 2018 at 10:32, Vinod wrote: > On 26-07-18, 16:00, Baolin Wang wrote: >> From: Eric Long >> >> The Spreadtrum DMA can support the link-list transaction mode, which means >> DMA controller can do transaction one by one automatically once we linked >> these transaction by link-list register. >> >> Signed-off-by: Eric Long >> Signed-off-by: Baolin Wang >> --- >> drivers/dma/sprd-dma.c | 82 ++++++++++++++++++++++++++++++++++++++---- >> include/linux/dma/sprd-dma.h | 69 +++++++++++++++++++++++++++++++++++ >> 2 files changed, 144 insertions(+), 7 deletions(-) >> >> diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c >> index 55df0d4..649bd2c 100644 >> --- a/drivers/dma/sprd-dma.c >> +++ b/drivers/dma/sprd-dma.c >> @@ -68,6 +68,7 @@ >> >> /* SPRD_DMA_CHN_CFG register definition */ >> #define SPRD_DMA_CHN_EN BIT(0) >> +#define SPRD_DMA_LINKLIST_EN BIT(4) >> #define SPRD_DMA_WAIT_BDONE_OFFSET 24 >> #define SPRD_DMA_DONOT_WAIT_BDONE 1 >> >> @@ -103,7 +104,7 @@ >> #define SPRD_DMA_REQ_MODE_MASK GENMASK(1, 0) >> #define SPRD_DMA_FIX_SEL_OFFSET 21 >> #define SPRD_DMA_FIX_EN_OFFSET 20 >> -#define SPRD_DMA_LLIST_END_OFFSET 19 >> +#define SPRD_DMA_LLIST_END BIT(19) >> #define SPRD_DMA_FRG_LEN_MASK GENMASK(16, 0) >> >> /* SPRD_DMA_CHN_BLK_LEN register definition */ >> @@ -164,6 +165,7 @@ struct sprd_dma_desc { >> struct sprd_dma_chn { >> struct virt_dma_chan vc; >> void __iomem *chn_base; >> + struct sprd_dma_linklist linklist; >> struct dma_slave_config slave_cfg; >> u32 chn_num; >> u32 dev_id; >> @@ -582,7 +584,8 @@ static int sprd_dma_get_step(enum dma_slave_buswidth buswidth) >> } >> >> static int sprd_dma_fill_desc(struct dma_chan *chan, >> - struct sprd_dma_desc *sdesc, >> + struct sprd_dma_chn_hw *hw, >> + unsigned int sglen, int sg_index, >> dma_addr_t src, dma_addr_t dst, u32 len, >> enum dma_transfer_direction dir, >> unsigned long flags, >> @@ -590,7 +593,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, >> { >> struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan); >> struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); >> - struct sprd_dma_chn_hw *hw = &sdesc->chn_hw; >> u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK; >> u32 int_mode = flags & SPRD_DMA_INT_MASK; >> int src_datawidth, dst_datawidth, src_step, dst_step; >> @@ -670,12 +672,58 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, >> temp |= (src_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET; >> hw->trsf_step = temp; >> >> + /* link-list configuration */ >> + if (schan->linklist.phy_addr) { >> + if (sg_index == sglen - 1) >> + hw->frg_len |= SPRD_DMA_LLIST_END; >> + >> + hw->cfg |= SPRD_DMA_LINKLIST_EN; >> + hw->llist_ptr = schan->linklist.phy_addr + >> + ((sg_index + 1) % sglen) * sizeof(*hw) + >> + SPRD_DMA_CHN_SRC_ADDR; >> + } else { >> + hw->llist_ptr = 0; >> + } >> + >> hw->frg_step = 0; >> hw->src_blk_step = 0; >> hw->des_blk_step = 0; >> return 0; >> } >> >> +static int sprd_dma_fill_linklist_desc(struct dma_chan *chan, >> + unsigned int sglen, int sg_index, >> + dma_addr_t src, dma_addr_t dst, u32 len, >> + enum dma_transfer_direction dir, >> + unsigned long flags, >> + struct dma_slave_config *slave_cfg) >> +{ >> + struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); >> + struct sprd_dma_chn_hw *hw; >> + >> + if (sglen < 2 || !schan->linklist.virt_addr) >> + return -EINVAL; > > why the limitation of 2 here? Spreadtrum DMA link-list mode needs more than 2 link-list configurations. If there is only one sg, it doesn't need to fill the link-list configuration. Moreover, we have valided the sg length in sprd_dma_prep_slave_sg(), so will remove the redundant validation here. > >> + >> + hw = (struct sprd_dma_chn_hw *)(schan->linklist.virt_addr + >> + sg_index * sizeof(*hw)); >> + >> + return sprd_dma_fill_desc(chan, hw, sglen, sg_index, src, dst, len, dir, >> + flags, slave_cfg); >> +} >> + >> +static int sprd_dma_fill_chn_desc(struct dma_chan *chan, >> + struct sprd_dma_desc *sdesc, >> + dma_addr_t src, dma_addr_t dst, u32 len, >> + enum dma_transfer_direction dir, >> + unsigned long flags, >> + struct dma_slave_config *slave_cfg) >> +{ >> + struct sprd_dma_chn_hw *hw = &sdesc->chn_hw; >> + >> + return sprd_dma_fill_desc(chan, hw, 0, 0, src, dst, len, dir, >> + flags, slave_cfg); >> +} > > this fn does not do much, so why not call sprd_dma_fill_desc() instead > from caller! OK, will fix it. > >> + >> static struct dma_async_tx_descriptor * >> sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, >> size_t len, unsigned long flags) >> @@ -744,10 +792,20 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, >> u32 len = 0; >> int ret, i; >> >> - /* TODO: now we only support one sg for each DMA configuration. */ >> - if (!is_slave_direction(dir) || sglen > 1) >> + if (!is_slave_direction(dir)) >> return NULL; >> >> + if (context) { >> + struct sprd_dma_linklist *ll_cfg = >> + (struct sprd_dma_linklist *)context; >> + >> + schan->linklist.phy_addr = ll_cfg->phy_addr; >> + schan->linklist.virt_addr = ll_cfg->virt_addr; >> + } else { >> + schan->linklist.phy_addr = 0; >> + schan->linklist.virt_addr = 0; >> + } >> + >> sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT); >> if (!sdesc) >> return NULL; >> @@ -762,10 +820,20 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, >> src = slave_cfg->src_addr; >> dst = sg_dma_address(sg); >> } >> + >> + if (sglen < 2) >> + break; > > ? Like I said above, dma link-list mode needs more than 2 configurations, I will add some comments to explain why. > >> + >> + ret = sprd_dma_fill_linklist_desc(chan, sglen, i, src, dst, len, >> + dir, flags, slave_cfg); >> + if (ret) { >> + kfree(sdesc); >> + return NULL; >> + } >> } >> >> - ret = sprd_dma_fill_desc(chan, sdesc, src, dst, len, dir, flags, >> - slave_cfg); >> + ret = sprd_dma_fill_chn_desc(chan, sdesc, src, dst, len, dir, flags, >> + slave_cfg); >> if (ret) { >> kfree(sdesc); >> return NULL; >> diff --git a/include/linux/dma/sprd-dma.h b/include/linux/dma/sprd-dma.h >> index b0115e3..c51c705 100644 >> --- a/include/linux/dma/sprd-dma.h >> +++ b/include/linux/dma/sprd-dma.h >> @@ -58,4 +58,73 @@ enum sprd_dma_int_type { >> SPRD_DMA_CFGERR_INT, >> }; >> >> +/* >> + * struct sprd_dma_linklist - DMA link-list address structure >> + * @virt_addr: link-list virtual address to configure link-list node >> + * @phy_addr: link-list physical address to link DMA transfer >> + * >> + * The Spreadtrum DMA controller supports the link-list mode, that means slaves >> + * can supply several groups configurations (each configuration represents one >> + * DMA transfer) saved in memory, and DMA controller will link these groups >> + * configurations by writing the physical address of each configuration into the >> + * link-list register. >> + * >> + * Just as shown below, the link-list pointer register will be pointed to the >> + * phycial address of 'configuration 1', and the 'configuration 1' link-list > > /s/phycial/physical Sorry for typos and will fix. > >> + * pointer will be pointed to 'configuration 2', and so on. >> + * Once trigger the DMA transfer, the DMA controller will load 'configureation > > /s/configureation/configuration Will fix. > >> + * 1' to its registers automatically, after 'configuration 1' transation is > > /s/transation/transaction Will fix. > >> + * done, DMA controller will load 'configuration 2' automatically, until all >> + * DMA transactions are done. >> + * >> + * Note: The last link-list pointer should point to the physical address >> + * of 'configuration 1', which can avoid DMA controller loads incorrect >> + * configuration when the last configuration transaction is done. >> + * >> + * DMA controller linklist memory >> + * ====================== ----------------------- >> + *| | | configuration 1 |<--- >> + *| DMA controller | ------->| | | >> + *| | | | | | >> + *| | | | | | >> + *| | | | | | >> + *| linklist pointer reg |---- ----| linklist pointer | | >> + * ====================== | ----------------------- | >> + * | | >> + * | ----------------------- | >> + * | | configuration 2 | | >> + * --->| | | >> + * | | | >> + * | | | >> + * | | | >> + * ----| linklist pointer | | >> + * | ----------------------- | >> + * | | >> + * | ----------------------- | >> + * | | configuration 3 | | >> + * --->| | | >> + * | | | >> + * | . | | >> + * . | >> + * . | >> + * . | >> + * | . | >> + * | ----------------------- | >> + * | | configuration n | | >> + * --->| | | >> + * | | | >> + * | | | >> + * | | | >> + * | linklist pointer |---- >> + * ----------------------- >> + * >> + * To support the link-list mode, DMA slaves should allocate one segment memory >> + * from always-on IRAM or dma coherent memory to store these groups of DMA >> + * configuration, and pass the virtual and physical addess to DMA controller. > > /s/addess/address Will fix in next version. Thanks for your comments. -- Baolin Wang Best Regards