Fix some bugs and add new feature for Spreadtrum DMA engine
Subsystems (2)
v2 cover Fix some bugs and add new feature for Spreadtrum DMA engine
Hi,
This patch set fixes some DMA engine bugs and adds interrupt support for 2-stage transfer.
Changes from v1:
- Improve the commit message for patch 1.
- Drop patch 4 from the v1 patch set, and I will create another patch set to move the fix to the core.
Baolin Wang (3):
dmaengine: sprd: Fix the possible crash when getting descriptor
status
dmaengine: sprd: Add validation of current descriptor in irq handler
dmaengine: sprd: Add interrupt support for 2-stage transfer
Eric Long (3):
dmaengine: sprd: Fix the incorrect start for 2-stage destination
channels
dmaengine: sprd: Fix block length overflow
dmaengine: sprd: Fix the right place to configure 2-stage transfer
drivers/dma/sprd-dma.c | 49 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 11 deletions(-)
Signature · 1 line
1.7.9.5
PATCH v2 1/6 dmaengine: sprd: Fix the possible crash when getting descriptor status
We will get a NULL virtual descriptor by vchan_find_desc() when the descriptor has been submitted, that will crash the kernel when getting the descriptor status.
In this case, since the descriptor has been submitted to process, but it is not completed now, which means the descriptor is listed into the 'vc->desc_submitted' list now. So we can not get current processing descriptor by vchan_find_desc(), but the pointer 'schan->cur_desc' will point to the current processing descriptor, then we can use 'schan->cur_desc' to get current processing descriptor's status to avoid this issue.
--- drivers/dma/sprd-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/sprd-dma.c +1 -1
@@ -625,7 +625,7 @@ static enum dma_status sprd_dma_tx_status(struct dma_chan *chan,else pos =0 ; }else if (schan->cur_desc && schan->cur_desc->vd.tx.cookie == cookie) { -struct sprd_dma_desc *sdesc =to_sprd_dma_desc (vd); +struct sprd_dma_desc *sdesc = schan->cur_desc;if (sdesc->dir ==DMA_DEV_TO_MEM ) pos =sprd_dma_get_dst_addr (schan);
Signature · 1 line
1.7.9.5
PATCH v2 2/6 dmaengine: sprd: Add validation of current descriptor in irq handler
In reply to Baolin WangWhen user terminates one DMA channel to free all its descriptors, but at the same time one transaction interrupt was triggered possibly, now we should not handle this interrupt by validating if the 'schan->cur_desc' was set as NULL to avoid crashing the kernel.
--- drivers/dma/sprd-dma.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/dma/sprd-dma.c +7 -2
@@ -552,12 +552,17 @@ static irqreturn_t dma_irq_handle(int irq, void *dev_id) schan = &sdev->channels[i];spin_lock (&schan->vc.lock); + + sdesc = schan->cur_desc; +if (!sdesc) { +spin_unlock (&schan->vc.lock); +return IRQ_HANDLED ; + } + int_type =sprd_dma_get_int_type (schan); req_type =sprd_dma_get_req_type (schan);sprd_dma_clear_int (schan); - sdesc = schan->cur_desc; -/* cyclic mode schedule callback */ cyclic = schan->linklist.phy_addr ? true : false;if (cyclic == true) {
Signature · 1 line
1.7.9.5
PATCH v2 3/6 dmaengine: sprd: Fix the incorrect start for 2-stage destination channels
In reply to Baolin WangFrom: Eric Long <[email protected]>
The 2-stage destination channel will be triggered by source channel automatically, which means we should not trigger it by software request.
--- drivers/dma/sprd-dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/dma/sprd-dma.c +3 -1
@@ -510,7 +510,9 @@ static void sprd_dma_start(struct sprd_dma_chn *schan)sprd_dma_set_uid (schan);sprd_dma_enable_chn (schan); -if (schan->dev_id ==SPRD_DMA_SOFTWARE_UID ) +if (schan->dev_id ==SPRD_DMA_SOFTWARE_UID && + schan->chn_mode !=SPRD_DMA_DST_CHN0 && + schan->chn_mode !=SPRD_DMA_DST_CHN1 )sprd_dma_soft_request (schan); }
Signature · 1 line
1.7.9.5
PATCH v2 4/6 dmaengine: sprd: Fix block length overflow
In reply to Baolin WangFrom: Eric Long <[email protected]>
The maximum value of block length is 0xffff, so if the configured transfer length is more than 0xffff, that will cause block length overflow to lead a configuration error.
Thus we can set block length as the maximum burst length to avoid this issue, since the maximum burst length will not be a big value which is more than 0xffff.
--- drivers/dma/sprd-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/sprd-dma.c +1 -1
@@ -778,7 +778,7 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, temp |= slave_cfg->src_maxburst &SPRD_DMA_FRG_LEN_MASK ; hw->frg_len = temp; - hw->blk_len = len &SPRD_DMA_BLK_LEN_MASK ; + hw->blk_len = slave_cfg->src_maxburst &SPRD_DMA_BLK_LEN_MASK ; hw->trsc_len = len &SPRD_DMA_TRSC_LEN_MASK ; temp = (dst_step &SPRD_DMA_TRSF_STEP_MASK ) <<SPRD_DMA_DEST_TRSF_STEP_OFFSET ;
Signature · 1 line
1.7.9.5
PATCH v2 5/6 dmaengine: sprd: Fix the right place to configure 2-stage transfer
In reply to Baolin WangFrom: Eric Long <[email protected]>
Move the 2-stage configuration before configuring the link-list mode, since we will use some 2-stage configuration to fill the link-list configuration.
--- drivers/dma/sprd-dma.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/dma/sprd-dma.c +6 -6
@@ -911,6 +911,12 @@ static int sprd_dma_fill_linklist_desc(struct dma_chan *chan, schan->linklist.virt_addr =0 ; } +/* Set channel mode and trigger mode for 2-stage transfer */ + schan->chn_mode = + (flags >>SPRD_DMA_CHN_MODE_SHIFT ) &SPRD_DMA_CHN_MODE_MASK ; + schan->trg_mode = + (flags >>SPRD_DMA_TRG_MODE_SHIFT ) &SPRD_DMA_TRG_MODE_MASK ; + sdesc =kzalloc (sizeof (*sdesc),GFP_NOWAIT );if (!sdesc)return NULL ;
@@ -944,12 +950,6 @@ static int sprd_dma_fill_linklist_desc(struct dma_chan *chan, } } -/* Set channel mode and trigger mode for 2-stage transfer */ - schan->chn_mode = - (flags >>SPRD_DMA_CHN_MODE_SHIFT ) &SPRD_DMA_CHN_MODE_MASK ; - schan->trg_mode = - (flags >>SPRD_DMA_TRG_MODE_SHIFT ) &SPRD_DMA_TRG_MODE_MASK ; - ret =sprd_dma_fill_desc (chan, &sdesc->chn_hw,0 ,0 , src, dst, len, dir, flags, slave_cfg);if (ret) {
Signature · 1 line
1.7.9.5
PATCH v2 6/6 dmaengine: sprd: Add interrupt support for 2-stage transfer
In reply to Baolin WangFor 2-stage transfer, some users like Audio still need transaction interrupt to notify when the 2-stage transfer is completed. Thus we should enable 2-stage transfer interrupt to support this feature.
--- drivers/dma/sprd-dma.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
drivers/dma/sprd-dma.c +21 -1
@@ -62,6 +62,8 @@/* SPRD_DMA_GLB_2STAGE_GRP register definition */ #define SPRD_DMA_GLB_2STAGE_EN BIT(24)#define SPRD_DMA_GLB_CHN_INT_MASK GENMASK(23, 20) +#define SPRD_DMA_GLB_DEST_INT BIT(22) +#define SPRD_DMA_GLB_SRC_INT BIT(20)#define SPRD_DMA_GLB_LIST_DONE_TRG BIT(19)#define SPRD_DMA_GLB_TRANS_DONE_TRG BIT(18)#define SPRD_DMA_GLB_BLOCK_DONE_TRG BIT(17)
@@ -135,6 +137,7 @@/* define DMA channel mode & trigger mode mask */ #define SPRD_DMA_CHN_MODE_MASK GENMASK(7, 0)#define SPRD_DMA_TRG_MODE_MASK GENMASK(7, 0) +#define SPRD_DMA_INT_TYPE_MASK GENMASK(7, 0)/* define the DMA transfer step type */ #define SPRD_DMA_NONE_STEP 0
@@ -190,6 +193,7 @@ struct sprd_dma_chn {u32 dev_id;enum sprd_dma_chn_mode chn_mode;enum sprd_dma_trg_mode trg_mode; +enum sprd_dma_int_type int_type;struct sprd_dma_desc *cur_desc; };
@@ -429,6 +433,9 @@ static int sprd_dma_set_2stage_config(struct sprd_dma_chn *schan) val = chn &SPRD_DMA_GLB_SRC_CHN_MASK ; val |=BIT (schan->trg_mode -1 ) <<SPRD_DMA_GLB_TRG_OFFSET ; val |=SPRD_DMA_GLB_2STAGE_EN ; +if (schan->int_type !=SPRD_DMA_NO_INT ) + val |=SPRD_DMA_GLB_SRC_INT ; +sprd_dma_glb_update (sdev,SPRD_DMA_GLB_2STAGE_GRP1 , val, val);break ;
@@ -436,6 +443,9 @@ static int sprd_dma_set_2stage_config(struct sprd_dma_chn *schan) val = chn &SPRD_DMA_GLB_SRC_CHN_MASK ; val |=BIT (schan->trg_mode -1 ) <<SPRD_DMA_GLB_TRG_OFFSET ; val |=SPRD_DMA_GLB_2STAGE_EN ; +if (schan->int_type !=SPRD_DMA_NO_INT ) + val |=SPRD_DMA_GLB_SRC_INT ; +sprd_dma_glb_update (sdev,SPRD_DMA_GLB_2STAGE_GRP2 , val, val);break ;
@@ -443,6 +453,9 @@ static int sprd_dma_set_2stage_config(struct sprd_dma_chn *schan) val = (chn <<SPRD_DMA_GLB_DEST_CHN_OFFSET ) &SPRD_DMA_GLB_DEST_CHN_MASK ; val |=SPRD_DMA_GLB_2STAGE_EN ; +if (schan->int_type !=SPRD_DMA_NO_INT ) + val |=SPRD_DMA_GLB_DEST_INT ; +sprd_dma_glb_update (sdev,SPRD_DMA_GLB_2STAGE_GRP1 , val, val);break ;
@@ -450,6 +463,9 @@ static int sprd_dma_set_2stage_config(struct sprd_dma_chn *schan) val = (chn <<SPRD_DMA_GLB_DEST_CHN_OFFSET ) &SPRD_DMA_GLB_DEST_CHN_MASK ; val |=SPRD_DMA_GLB_2STAGE_EN ; +if (schan->int_type !=SPRD_DMA_NO_INT ) + val |=SPRD_DMA_GLB_DEST_INT ; +sprd_dma_glb_update (sdev,SPRD_DMA_GLB_2STAGE_GRP2 , val, val);break ;
@@ -911,11 +927,15 @@ static int sprd_dma_fill_linklist_desc(struct dma_chan *chan, schan->linklist.virt_addr =0 ; } -/* Set channel mode and trigger mode for 2-stage transfer */ +/* +* Set channel mode, interrupt mode and trigger mode for 2-stage +* transfer. +*/ schan->chn_mode = (flags >>SPRD_DMA_CHN_MODE_SHIFT ) &SPRD_DMA_CHN_MODE_MASK ; schan->trg_mode = (flags >>SPRD_DMA_TRG_MODE_SHIFT ) &SPRD_DMA_TRG_MODE_MASK ; + schan->int_type = flags &SPRD_DMA_INT_TYPE_MASK ; sdesc =kzalloc (sizeof (*sdesc),GFP_NOWAIT );if (!sdesc)
Signature · 1 line
1.7.9.5
Quoted 4 lines · Baolin Wang
Hi,
This patch set fixes some DMA engine bugs and adds interrupt support for 2-stage transfer.
Applied all, thanks
Signature · 1 line
~Vinod