dmaengine: dw-axi_dmac: bug fix clean up and more features
Subsystems (2)
cover dmaengine: dw-axi_dmac: bug fix clean up and more features
This series first fix a bug related with runtime pm. Then do three clean up. After that, we add three new features: per channel irq support, dma-channel-mask support and polled mode support.
Jisheng Zhang (11):
dmaengine: dw-axi-dmac: fix reading register hen runtime suspended
dmaengine: dw-axi-dmac: remove unnecessary devm_free_irq() calling
dmaengine: dw-axi-dmac: remove unnecessary axi_dma_enable() calling
dmaengine: dw-axi-dmac: remove redudant axi_dma_disable() calling
dmaengine: dw-axi-dmac: delay irq getting until request_irq
dmaengine: dw-axi-dmac: move ch irq handling into common routine
dmaengine: dw-axi-dmac: support per channel irq
dmaengine: dw-axi-dmac: support dma-channel-mask
dmaengine: dw-axi-dmac: try best to get residue when tx is running
dmaengine: dw-axi-dmac: move dma_chan_tx_status()
dmaengine: dw-axi-dmac: support polled mode
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 207 ++++++++++++------ drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 4 + 2 files changed, 147 insertions(+), 64 deletions(-)
Signature · 1 line
2.39.2
PATCH 1/11 dmaengine: dw-axi-dmac: fix reading register hen runtime suspended
We should runtime resume the device before calling axi_chan_is_hw_enable().
--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +11 -4
@@ -462,13 +462,17 @@ static void dw_axi_dma_synchronize(struct dma_chan *dchan)static int dma_chan_alloc_chan_resources (struct dma_chan *dchan) { +int ret;struct axi_dma_chan *chan =dchan_to_axi_dma_chan (dchan); +pm_runtime_get (chan->chip->dev); +/* ASSERT: channel is idle */ if (axi_chan_is_hw_enable (chan)) {dev_err (chan2dev (chan),"%s is non-idle!\n" ,axi_chan_name (chan)); -return -EBUSY ; + ret = -EBUSY ; + goto err_busy; }/* LLI address must be aligned to a 64-byte boundary */
@@ -478,13 +482,16 @@ static int dma_chan_alloc_chan_resources(struct dma_chan *dchan) 64, 0);if (!chan->desc_pool) {dev_err (chan2dev (chan),"No memory for descriptors\n" ); -return -ENOMEM ; + ret = -ENOMEM ; + goto err_busy; }dev_vdbg (dchan2dev (dchan),"%s: allocating\n" ,axi_chan_name (chan)); -pm_runtime_get (chan->chip->dev); -return 0 ; + +err_busy: +pm_runtime_put (chan->chip->dev); +return ret; }static void dma_chan_free_chan_resources (struct dma_chan *dchan)
Signature · 1 line
2.39.2
Vinod Koul
maintainerRe: [PATCH 01/11] dmaengine: dw-axi-dmac: fix reading register hen runtime suspended
s/hen/when..? or something else
Quoted 2 lines · Jisheng Zhang
We should runtime resume the device before calling
axi_chan_is_hw_enable().
why is that can you please explain..
Quoted 51 lines
Signed-off-by Jisheng Zhang <[email protected]>--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +11
-4@@ -462,13 +462,17 @@ static void dw_axi_dma_synchronize(struct dma_chan *dchan)static int dma_chan_alloc_chan_resources (struct dma_chan *dchan) { +int ret;struct axi_dma_chan *chan =dchan_to_axi_dma_chan (dchan); +pm_runtime_get (chan->chip->dev); +/* ASSERT: channel is idle */ if (axi_chan_is_hw_enable (chan)) {dev_err (chan2dev (chan),"%s is non-idle!\n" ,axi_chan_name (chan)); -return -EBUSY ; + ret = -EBUSY ; + goto err_busy; }/* LLI address must be aligned to a 64-byte boundary */ @@ -478,13 +482,16 @@ static int dma_chan_alloc_chan_resources(struct dma_chan *dchan) 64, 0);if (!chan->desc_pool) {dev_err (chan2dev (chan),"No memory for descriptors\n" ); -return -ENOMEM ; + ret = -ENOMEM ; + goto err_busy; }dev_vdbg (dchan2dev (dchan),"%s: allocating\n" ,axi_chan_name (chan)); -pm_runtime_get (chan->chip->dev); -return 0 ; + +err_busy: +pm_runtime_put (chan->chip->dev); +return ret; }static void dma_chan_free_chan_resources (struct dma_chan *dchan)Signature · 1 line
2.39.2
Signature · 1 line
~Vinod
Re: [PATCH 01/11] dmaengine: dw-axi-dmac: fix reading register hen runtime suspended
Quoted 7 lines · Vinod Koul
s/hen/when..? or something else
Quoted 2 lines · Jisheng Zhang
We should runtime resume the device before calling
axi_chan_is_hw_enable().why is that can you please explain..
If the device is suspended, I.E not resumed, accessing any registers in axi_chan_is_hw_enable() will cause cpu abort.
I will add this info into commit log of v2.
Quoted 55 lines
Quoted 52 lines
Signed-off-by Jisheng Zhang <[email protected]>--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +11
-4@@ -462,13 +462,17 @@ static void dw_axi_dma_synchronize(struct dma_chan *dchan)static int dma_chan_alloc_chan_resources (struct dma_chan *dchan) { +int ret;struct axi_dma_chan *chan =dchan_to_axi_dma_chan (dchan); +pm_runtime_get (chan->chip->dev); +/* ASSERT: channel is idle */ if (axi_chan_is_hw_enable (chan)) {dev_err (chan2dev (chan),"%s is non-idle!\n" ,axi_chan_name (chan)); -return -EBUSY ; + ret = -EBUSY ; + goto err_busy; }/* LLI address must be aligned to a 64-byte boundary */ @@ -478,13 +482,16 @@ static int dma_chan_alloc_chan_resources(struct dma_chan *dchan) 64, 0);if (!chan->desc_pool) {dev_err (chan2dev (chan),"No memory for descriptors\n" ); -return -ENOMEM ; + ret = -ENOMEM ; + goto err_busy; }dev_vdbg (dchan2dev (dchan),"%s: allocating\n" ,axi_chan_name (chan)); -pm_runtime_get (chan->chip->dev); -return 0 ; + +err_busy: +pm_runtime_put (chan->chip->dev); +return ret; }static void dma_chan_free_chan_resources (struct dma_chan *dchan)Signature · 1 line
2.39.2Signature · 1 line
~Vinod
PATCH 2/11 dmaengine: dw-axi-dmac: remove unnecessary devm_free_irq() calling
In reply to Jisheng ZhangIn dw_remove(), We have disabled the irq from the dw-axi-dma side, so we are safe against the case "The irq is still ON when devices remove is executed and irq should be quiesced before remove is completed."
--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- 1 file changed, 2 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +0 -2
@@ -1542,8 +1542,6 @@ static int dw_remove(struct platform_device *pdev)pm_runtime_disable (chip->dev);axi_dma_suspend (chip); -devm_free_irq (chip->dev, chip->irq, chip); -of_dma_controller_free (chip->dev->of_node); list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
Signature · 1 line
2.39.2
Vinod Koul
maintainerRe: [PATCH 02/11] dmaengine: dw-axi-dmac: remove unnecessary devm_free_irq() calling
Quoted 3 lines · Jisheng Zhang
In
dw_remove(), We have disabled the irq from the dw-axi-dma side, so we are safe against the case "The irq is still ON when devices remove is executed and irq should be quiesced before remove is completed."
what about the interrupts which might fire spuriously after this? I prefer to keep this explicitly here
Quoted 21 lines
Signed-off-by Jisheng Zhang <[email protected]>--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- 1 file changed, 2 deletions(-)drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +0
-2@@ -1542,8 +1542,6 @@ static int dw_remove(struct platform_device *pdev)pm_runtime_disable (chip->dev);axi_dma_suspend (chip); -devm_free_irq (chip->dev, chip->irq, chip); -of_dma_controller_free (chip->dev->of_node); list_for_each_entry_safe(chan, _chan, &dw->dma.channels,Signature · 1 line
2.39.2
Signature · 1 line
~Vinod
Re: [PATCH 02/11] dmaengine: dw-axi-dmac: remove unnecessary devm_free_irq() calling
Quoted 6 lines · Vinod Koul
Quoted 3 lines · Jisheng Zhang
In
dw_remove(), We have disabled the irq from the dw-axi-dma side, so we are safe against the case "The irq is still ON when devices remove is executed and irq should be quiesced before remove is completed."what about the interrupts which might fire spuriously after this? I
This is impossible becuase the irq has been disabled from the dw-axi-dma side.
Quoted 25 lines
prefer to keep this explicitly here
Quoted 21 lines
Signed-off-by Jisheng Zhang <[email protected]>--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- 1 file changed, 2 deletions(-)drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +0
-2@@ -1542,8 +1542,6 @@ static int dw_remove(struct platform_device *pdev)pm_runtime_disable (chip->dev);axi_dma_suspend (chip); -devm_free_irq (chip->dev, chip->irq, chip); -of_dma_controller_free (chip->dev->of_node); list_for_each_entry_safe(chan, _chan, &dw->dma.channels,Signature · 1 line
2.39.2Signature · 1 line
~Vinod
PATCH 3/11 dmaengine: dw-axi-dmac: remove unnecessary axi_dma_enable() calling
In reply to Jisheng ZhangThe dma is enabled, I.E runtime resumed during chan allocation, and is disable, I.E runtime suspended during chan free. So when starting xfer, we are sure the dma is enabled.
--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- 1 file changed, 2 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +0 -2
@@ -382,8 +382,6 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,return ; } -axi_dma_enable (chan->chip); - config.dst_multblk_type =DWAXIDMAC_MBLK_TYPE_LL ; config.src_multblk_type =DWAXIDMAC_MBLK_TYPE_LL ; config.tt_fc =DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC ;
Signature · 1 line
2.39.2
PATCH 4/11 dmaengine: dw-axi-dmac: remove redudant axi_dma_disable() calling
In reply to Jisheng Zhangaxi_dma_suspend() will soon call axi_dma_disable(), remove the redudant axi_dma_disable() callin.
--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 1 - 1 file changed, 1 deletion(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +0 -1
@@ -1535,7 +1535,6 @@ static int dw_remove(struct platform_device *pdev)axi_chan_disable (&chip->dw->chan[i]);axi_chan_irq_disable (&chip->dw->chan[i],DWAXIDMAC_IRQ_ALL ); } -axi_dma_disable (chip);pm_runtime_disable (chip->dev);axi_dma_suspend (chip);
Signature · 1 line
2.39.2
Vinod Koul
maintainerRe: [PATCH 04/11] dmaengine: dw-axi-dmac: remove redudant axi_dma_disable() calling
Quoted 1 line · Jisheng Zhang
axi_dma_suspend()will soon callaxi_dma_disable(), remove the redudant
s/redudant/redundant
Quoted 21 lines
axi_dma_disable()callin.Signed-off-by Jisheng Zhang <[email protected]>--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 1 - 1 file changed, 1 deletion(-)drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +0
-1@@ -1535,7 +1535,6 @@ static int dw_remove(struct platform_device *pdev)axi_chan_disable (&chip->dw->chan[i]);axi_chan_irq_disable (&chip->dw->chan[i],DWAXIDMAC_IRQ_ALL ); } -axi_dma_disable (chip);pm_runtime_disable (chip->dev);axi_dma_suspend (chip);Signature · 1 line
2.39.2
Signature · 1 line
~Vinod
PATCH 5/11 dmaengine: dw-axi-dmac: delay irq getting until request_irq
In reply to Jisheng ZhangThis is to prepare for per-channel irq support in next patch. In per-channel irq case, we need to parse dt firstly to know whether the platform is per-channel irq or not.
--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +4 -4
@@ -1395,10 +1395,6 @@ static int dw_probe(struct platform_device *pdev) chip->dev = &pdev->dev; chip->dw->hdata = hdata; - chip->irq =platform_get_irq (pdev,0 ); -if (chip->irq <0 ) -return chip->irq; - chip->regs =devm_platform_ioremap_resource (pdev,0 );if (IS_ERR (chip->regs))return PTR_ERR (chip->regs);
@@ -1426,6 +1422,10 @@ static int dw_probe(struct platform_device *pdev)if (!dw->chan)return -ENOMEM ; + chip->irq =platform_get_irq (pdev,0 ); +if (chip->irq <0 ) +return chip->irq; + ret =devm_request_irq (chip->dev, chip->irq, dw_axi_dma_interrupt,IRQF_SHARED ,KBUILD_MODNAME , chip);if (ret)
Signature · 1 line
2.39.2
PATCH 6/11 dmaengine: dw-axi-dmac: move ch irq handling into common routine
In reply to Jisheng ZhangIn next patch, we will add per-channel irq support, we will use the common routine in per-channel irq handler.
--- .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +19 -11
@@ -1101,13 +1101,30 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)spin_unlock_irqrestore (&chan->vc.lock, flags); } +static void dw_axi_dma_handle_ch (struct axi_dma_chan *chan) +{ +u32 status; + +/* Poll, clear and process this channel interrupt status */ + status =axi_chan_irq_read (chan); +axi_chan_irq_clear (chan, status); + +dev_vdbg (chan->chip->dev,"%s IRQ status: 0x%08x\n" ,axi_chan_name (chan), status); + +if (status &DWAXIDMAC_IRQ_ALL_ERR ) +axi_chan_handle_err (chan, status); +else if (status &DWAXIDMAC_IRQ_DMA_TRF ) +axi_chan_block_xfer_complete (chan); + +} +static irqreturn_t dw_axi_dma_interrupt (int irq,void *dev_id) {struct axi_dma_chip *chip = dev_id;struct dw_axi_dma *dw = chip->dw;struct axi_dma_chan *chan; -u32 status, i; +u32 i;/* Disable DMAC interrupts. We'll enable them after processing channels */ axi_dma_irq_disable (chip);
@@ -1115,16 +1132,7 @@ static irqreturn_t dw_axi_dma_interrupt(int irq, void *dev_id)/* Poll, clear and process every channel interrupt status */ for (i =0 ; i < dw->hdata->nr_channels; i++) { chan = &dw->chan[i]; - status =axi_chan_irq_read (chan); -axi_chan_irq_clear (chan, status); - -dev_vdbg (chip->dev,"%s %u IRQ status: 0x%08x\n" , -axi_chan_name (chan), i, status); - -if (status &DWAXIDMAC_IRQ_ALL_ERR ) -axi_chan_handle_err (chan, status); -else if (status &DWAXIDMAC_IRQ_DMA_TRF ) -axi_chan_block_xfer_complete (chan); +dw_axi_dma_handle_ch (chan); }/* Re-enable interrupts */
Signature · 1 line
2.39.2
PATCH 7/11 dmaengine: dw-axi-dmac: support per channel irq
In reply to Jisheng ZhangEach channel can have its own irq, support this case.
--- .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 48 +++++++++++++++---- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 2 + 2 files changed, 42 insertions(+), 8 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +40 -8
@@ -1141,6 +1141,21 @@ static irqreturn_t dw_axi_dma_interrupt(int irq, void *dev_id)return IRQ_HANDLED ; } +static irqreturn_t dw_axi_dma_ch_interrupt (int irq,void *dev_id) +{ +struct axi_dma_chan *chan = dev_id; + +/* Disable DMAC interrupts. We'll enable them after processing channels */ +axi_chan_irq_sig_set (chan,DWAXIDMAC_IRQ_NONE ); + +dw_axi_dma_handle_ch (chan); + +/* Re-enable interrupts */ +axi_chan_irq_sig_set (chan,DWAXIDMAC_IRQ_DMA_TRF |DWAXIDMAC_IRQ_ALL_ERR ); + +return IRQ_HANDLED ; +} +static int dma_chan_terminate_all (struct dma_chan *dchan) {struct axi_dma_chan *chan =dchan_to_axi_dma_chan (dchan);
@@ -1375,6 +1390,8 @@ static int parse_device_properties(struct axi_dma_chip *chip) chip->dw->hdata->axi_rw_burst_len = tmp; } + chip->dw->hdata->perch_irq =device_property_read_bool (dev,"snps,perch_irq" ); +return 0 ; }
@@ -1430,14 +1447,29 @@ static int dw_probe(struct platform_device *pdev)if (!dw->chan)return -ENOMEM ; - chip->irq =platform_get_irq (pdev,0 ); -if (chip->irq <0 ) -return chip->irq; - - ret =devm_request_irq (chip->dev, chip->irq, dw_axi_dma_interrupt, -IRQF_SHARED ,KBUILD_MODNAME , chip); -if (ret) -return ret; +if (hdata->perch_irq) { +char irqname[8 ]; +for (i =0 ; i < hdata->nr_channels; i++) { +snprintf (irqname,sizeof (irqname),"ch%u" , i); + dw->chan[i].irq =platform_get_irq_byname (pdev, irqname); +if (dw->chan[i].irq <0 ) +return dw->chan[i].irq; + ret =devm_request_irq (chip->dev, dw->chan[i].irq, + dw_axi_dma_ch_interrupt, +0 ,KBUILD_MODNAME , &dw->chan[i]); +if (ret) +return ret; + } + }else { + chip->irq =platform_get_irq (pdev,0 ); +if (chip->irq <0 ) +return chip->irq; + + ret =devm_request_irq (chip->dev, chip->irq, dw_axi_dma_interrupt, +IRQF_SHARED ,KBUILD_MODNAME , chip); +if (ret) +return ret; + }INIT_LIST_HEAD (&dw->dma.channels);for (i =0 ; i < hdata->nr_channels; i++) {
drivers/dma/dw-axi-dmac/dw-axi-dmac.h +2 -0
@@ -33,6 +33,7 @@ struct dw_axi_dma_hcfg {/* Register map for DMAX_NUM_CHANNELS <= 8 */ bool reg_map_8_channels;bool restrict_axi_burst_len; +bool perch_irq; };struct axi_dma_chan {
@@ -48,6 +49,7 @@ struct axi_dma_chan {struct axi_dma_desc *desc;struct dma_slave_config config;enum dma_transfer_direction direction; +int irq;bool cyclic;/* these other elements are all protected by vc.lock */ bool is_paused;
Signature · 1 line
2.39.2
PATCH 8/11 dmaengine: dw-axi-dmac: support dma-channel-mask
In reply to Jisheng ZhangSome dma channels may not be available, so we need to tell the driver the available dma channels, use the general dt binding "dma-channel-mask" for this purpose.
--- .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 19 +++++++++++++++++++ drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 + 2 files changed, 20 insertions(+)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +19 -0
@@ -216,6 +216,8 @@ static void axi_dma_hw_init(struct axi_dma_chip *chip)u32 i;for (i =0 ; i < chip->dw->hdata->nr_channels; i++) { +if (!(chip->dw->hdata->channels_mask & (1 << i))) +continue ;axi_chan_irq_disable (&chip->dw->chan[i],DWAXIDMAC_IRQ_ALL );axi_chan_disable (&chip->dw->chan[i]); }
@@ -1390,6 +1392,14 @@ static int parse_device_properties(struct axi_dma_chip *chip) chip->dw->hdata->axi_rw_burst_len = tmp; } +/* +* Use all channels if there's no dma-channel-mask property +*/ + ret =device_property_read_u32 (dev,"dma-channel-mask" , &tmp); +if (ret) + tmp =GENMASK (chip->dw->hdata->nr_channels -1 ,0 ); + chip->dw->hdata->channels_mask = tmp; + chip->dw->hdata->perch_irq =device_property_read_bool (dev,"snps,perch_irq" );return 0 ;
@@ -1450,6 +1460,10 @@ static int dw_probe(struct platform_device *pdev)if (hdata->perch_irq) {char irqname[8 ];for (i =0 ; i < hdata->nr_channels; i++) { +if (!(hdata->channels_mask & (1 << i))) { + dw->chan[i].irq =-1 ; +continue ; + }snprintf (irqname,sizeof (irqname),"ch%u" , i); dw->chan[i].irq =platform_get_irq_byname (pdev, irqname);if (dw->chan[i].irq <0 )
@@ -1475,6 +1489,9 @@ static int dw_probe(struct platform_device *pdev)for (i =0 ; i < hdata->nr_channels; i++) {struct axi_dma_chan *chan = &dw->chan[i]; +if (!(hdata->channels_mask & (1 << i))) +continue ; + chan->chip = chip; chan->id = i; chan->chan_regs = chip->regs +COMMON_REG_LEN + i *CHAN_REG_LEN ;
@@ -1572,6 +1589,8 @@ static int dw_remove(struct platform_device *pdev)clk_prepare_enable (chip->core_clk);axi_dma_irq_disable (chip);for (i =0 ; i < dw->hdata->nr_channels; i++) { +if (!(dw->hdata->channels_mask & (1 << i))) +continue ;axi_chan_disable (&chip->dw->chan[i]);axi_chan_irq_disable (&chip->dw->chan[i],DWAXIDMAC_IRQ_ALL ); }
drivers/dma/dw-axi-dmac/dw-axi-dmac.h +1 -0
@@ -30,6 +30,7 @@ struct dw_axi_dma_hcfg {u32 priority[DMAC_MAX_CHANNELS ];/* maximum supported axi burst length */ u32 axi_rw_burst_len; +u32 channels_mask;/* Register map for DMAX_NUM_CHANNELS <= 8 */ bool reg_map_8_channels;bool restrict_axi_burst_len;
Signature · 1 line
2.39.2
PATCH 9/11 dmaengine: dw-axi-dmac: try best to get residue when tx is running
In reply to Jisheng ZhangWhen tx is running, vchan_find_desc() will return NULL, try our best to get the residue in this case.
--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +12 -3
@@ -305,6 +305,7 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, struct dma_tx_state *txstate) {struct axi_dma_chan *chan =dchan_to_axi_dma_chan (dchan); +struct axi_dma_desc *desc =NULL ;struct virt_dma_desc *vdesc;enum dma_status status;u32 completed_length;
@@ -322,9 +323,15 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, vdesc =vchan_find_desc (&chan->vc, cookie);if (vdesc) { - length =vd_to_axi_desc (vdesc)->length; - completed_blocks =vd_to_axi_desc (vdesc)->completed_blocks; - len =vd_to_axi_desc (vdesc)->hw_desc[0 ].len; + desc =vd_to_axi_desc (vdesc); + }else if (chan->desc && chan->desc->vd.tx.cookie == cookie) { + desc = chan->desc; + } + +if (desc) { + length = desc->length; + completed_blocks = desc->completed_blocks; + len = desc->hw_desc[0 ].len; completed_length = completed_blocks * len; bytes = length - completed_length; }
@@ -425,6 +432,7 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,axi_chan_irq_set (chan, irq_mask);axi_chan_enable (chan); + chan->desc = first; }static void axi_chan_start_first_queued (struct axi_dma_chan *chan)
@@ -1188,6 +1196,7 @@ static int dma_chan_terminate_all(struct dma_chan *dchan)spin_unlock_irqrestore (&chan->vc.lock, flags);vchan_dma_desc_free_list (&chan->vc, &head); + chan->desc =NULL ;dev_vdbg (dchan2dev (dchan),"terminated: %s\n" ,axi_chan_name (chan));
Signature · 1 line
2.39.2
PATCH 10/11 dmaengine: dw-axi-dmac: move dma_chan_tx_status()
In reply to Jisheng ZhangWe will add polled support soon, for which we need to call dw_axi_dma_handle_ch() in dma_chan_tx_status(). Move the function to avoid pre-declaration.
No functionality changes.
--- .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +42 -42
@@ -300,48 +300,6 @@ static void vchan_desc_put(struct virt_dma_desc *vdesc)axi_desc_put (vd_to_axi_desc (vdesc)); } -static enum dma_status -dma_chan_tx_status (struct dma_chan *dchan,dma_cookie_t cookie, -struct dma_tx_state *txstate) -{ -struct axi_dma_chan *chan =dchan_to_axi_dma_chan (dchan); -struct axi_dma_desc *desc =NULL ; -struct virt_dma_desc *vdesc; -enum dma_status status; -u32 completed_length; -unsigned long flags; -u32 completed_blocks; -size_t bytes =0 ; -u32 length; -u32 len; - - status =dma_cookie_status (dchan, cookie, txstate); -if (status ==DMA_COMPLETE || !txstate) -return status; - -spin_lock_irqsave (&chan->vc.lock, flags); - - vdesc =vchan_find_desc (&chan->vc, cookie); -if (vdesc) { - desc =vd_to_axi_desc (vdesc); - }else if (chan->desc && chan->desc->vd.tx.cookie == cookie) { - desc = chan->desc; - } - -if (desc) { - length = desc->length; - completed_blocks = desc->completed_blocks; - len = desc->hw_desc[0 ].len; - completed_length = completed_blocks * len; - bytes = length - completed_length; - } - -spin_unlock_irqrestore (&chan->vc.lock, flags); -dma_set_residue (txstate, bytes); - -return status; -} -static void write_desc_llp (struct axi_dma_hw_desc *desc,dma_addr_t adr) { desc->lli->llp =cpu_to_le64 (adr);
@@ -1166,6 +1124,48 @@ static irqreturn_t dw_axi_dma_ch_interrupt(int irq, void *dev_id)return IRQ_HANDLED ; } +static enum dma_status +dma_chan_tx_status (struct dma_chan *dchan,dma_cookie_t cookie, +struct dma_tx_state *txstate) +{ +struct axi_dma_chan *chan =dchan_to_axi_dma_chan (dchan); +struct axi_dma_desc *desc =NULL ; +struct virt_dma_desc *vdesc; +enum dma_status status; +u32 completed_length; +unsigned long flags; +u32 completed_blocks; +size_t bytes =0 ; +u32 length; +u32 len; + + status =dma_cookie_status (dchan, cookie, txstate); +if (status ==DMA_COMPLETE || !txstate) +return status; + +spin_lock_irqsave (&chan->vc.lock, flags); + + vdesc =vchan_find_desc (&chan->vc, cookie); +if (vdesc) { + desc =vd_to_axi_desc (vdesc); + }else if (chan->desc && chan->desc->vd.tx.cookie == cookie) { + desc = chan->desc; + } + +if (desc) { + length = desc->length; + completed_blocks = desc->completed_blocks; + len = desc->hw_desc[0 ].len; + completed_length = completed_blocks * len; + bytes = length - completed_length; + } + +spin_unlock_irqrestore (&chan->vc.lock, flags); +dma_set_residue (txstate, bytes); + +return status; +} +static int dma_chan_terminate_all (struct dma_chan *dchan) {struct axi_dma_chan *chan =dchan_to_axi_dma_chan (dchan);
Signature · 1 line
2.39.2
PATCH 11/11 dmaengine: dw-axi-dmac: support polled mode
In reply to Jisheng ZhangRun in polled mode if the DMA_PREP_INTERRUPT flag is not provided.
--- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 11 ++++++++++- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +10 -1
@@ -383,7 +383,10 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,write_chan_llp (chan, first->hw_desc[0 ].llp | lms); irq_mask =DWAXIDMAC_IRQ_DMA_TRF |DWAXIDMAC_IRQ_ALL_ERR ; -axi_chan_irq_sig_set (chan, irq_mask); +if (chan->polled) +axi_chan_irq_sig_set (chan,DWAXIDMAC_IRQ_NONE ); +else +axi_chan_irq_sig_set (chan, irq_mask);/* Generate 'suspend' status but don't generate interrupt */ irq_mask |=DWAXIDMAC_IRQ_SUSPENDED ;
@@ -714,6 +717,7 @@ dw_axi_dma_chan_prep_cyclic(struct dma_chan *dchan, dma_addr_t dma_addr,if (unlikely (!desc)) goto err_desc_get; + chan->polled = !(flags &DMA_PREP_INTERRUPT ); chan->direction = direction; desc->chan = chan; chan->cyclic = true;
@@ -796,6 +800,7 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, desc->chan = chan; desc->length =0 ; + chan->polled = !(flags &DMA_PREP_INTERRUPT ); chan->direction = direction;for_each_sg (sgl, sg, sg_len, i) {
@@ -859,6 +864,7 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr,if (unlikely (!desc)) goto err_desc_get; + chan->polled = !(flags &DMA_PREP_INTERRUPT ); desc->chan = chan; num =0 ; desc->length =0 ;
@@ -1139,6 +1145,9 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,u32 length;u32 len; +if (chan->polled) +dw_axi_dma_handle_ch (chan); + status =dma_cookie_status (dchan, cookie, txstate);if (status ==DMA_COMPLETE || !txstate)return status;
drivers/dma/dw-axi-dmac/dw-axi-dmac.h +1 -0
@@ -54,6 +54,7 @@ struct axi_dma_chan {bool cyclic;/* these other elements are all protected by vc.lock */ bool is_paused; +bool polled; };struct dw_axi_dma {
Signature · 1 line
2.39.2