Hi bruce

Please help me merge this patch to branch 
v5.15/standard/preempt-rt/nxp-sdk-5.15/nxp-soc and 
v5.15/standard/nxp-sdk-5.15/nxp-soc

Thanks
Xiaolei


-----Original Message-----
From: [email protected] <[email protected]> 
On Behalf Of Xiaolei Wang via lists.yoctoproject.org
Sent: Tuesday, November 15, 2022 11:39 AM
To: [email protected]
Cc: [email protected]
Subject: [linux-yocto] [kernel-source][PATCH 2/2] LF-5352: dmaengine: imx-sdma: 
fix the potential access registers without clock

From: Joy Zou <[email protected]>

commit 5590650c9640d86cb63f9f669242498004bac80d from 
https://source.codeaurora.org/external/imx/linux-imx

The issue can be triggered with the sdma pm_runtime false.

If the dma client try to use sdma in boot phase, it may cause system hang. The 
sdma driver really enable clk after sdma load firmware, the clk_disable_unused 
will disable the SDMA1_ROOT_CLK before the sdma driver enable clk. This issue 
will comes if access the sdma register when the SDMA1_ROOT_CLK is disable.

This issue is very easy to reproduce with hdmi connected displayer on imx7d-sbd 
board which the i2c will use sdma early before sdma firmware loaded and clock 
enabled.

The client i2c calls dmaengine_prep_slave_single->device_prep_slave_sg
->sdma_prep_slave_sg->sdma_config_write->sdma_config_channel to get
descriptor in boot phase. Then, the function sdma_config_channel will access 
sdma registers. If clk is disable will cause system hang.

This patch adds clk_enable and clk_disable to make sure the clk enable before 
access sdma hardware.

Signed-off-by: Joy Zou <[email protected]>
Reviewed-by: Shengjiu Wang <[email protected]>
Reviewed-by: Dong Aisheng <[email protected]>
Signed-off-by: Xiaolei Wang <[email protected]>
---
 drivers/dma/imx-sdma.c | 105 +++++++++++++++++------------------------
 1 file changed, 43 insertions(+), 62 deletions(-)

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 
02a0aa072364..5d9efef28929 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -715,6 +715,30 @@ MODULE_DEVICE_TABLE(of, sdma_dt_ids);
 #define SDMA_H_CONFIG_ACR      BIT(4)  /* indicates if AHB freq /core freq = 2 
or 1 */
 #define SDMA_H_CONFIG_CSM      (3)       /* indicates which context switch 
mode is selected*/
 
+static void sdma_pm_clk_enable(struct sdma_engine *sdma, bool direct, 
+bool enable) {
+       if (enable) {
+               if (sdma->drvdata->pm_runtime)
+                       pm_runtime_get_sync(sdma->dev);
+               else {
+                       clk_enable(sdma->clk_ipg);
+                       clk_enable(sdma->clk_ahb);
+               }
+       } else {
+               if (sdma->drvdata->pm_runtime) {
+                       if (direct) {
+                               pm_runtime_put_sync_suspend(sdma->dev);
+                       } else {
+                               pm_runtime_mark_last_busy(sdma->dev);
+                               pm_runtime_put_autosuspend(sdma->dev);
+                       }
+               } else {
+                       clk_disable(sdma->clk_ipg);
+                       clk_disable(sdma->clk_ahb);
+               }
+       }
+}
+
 static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)  {
        u32 chnenbl0 = sdma->drvdata->chnenbl0; @@ -1057,13 +1081,7 @@ static 
irqreturn_t sdma_int_handler(int irq, void *dev_id)
        struct sdma_engine *sdma = dev_id;
        unsigned long stat;
 
-       if (sdma->drvdata->pm_runtime)
-               pm_runtime_get_sync(sdma->dev);
-       else {
-               clk_enable(sdma->clk_ipg);
-               clk_enable(sdma->clk_ahb);
-       }
-
+       sdma_pm_clk_enable(sdma, false, true);
        stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
        writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
        /* channel 0 is special and not handled here, see run_channel0() */ @@ 
-1093,13 +1111,7 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
                __clear_bit(channel, &stat);
        }
 
-       if (sdma->drvdata->pm_runtime) {
-               pm_runtime_mark_last_busy(sdma->dev);
-               pm_runtime_put_autosuspend(sdma->dev);
-       } else {
-               clk_disable(sdma->clk_ipg);
-               clk_disable(sdma->clk_ahb);
-       }
+       sdma_pm_clk_enable(sdma, false, false);
 
        return IRQ_HANDLED;
 }
@@ -1356,9 +1368,7 @@ static int sdma_terminate_all(struct dma_chan *chan)
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        unsigned long flags;
 
-       if (sdmac->sdma->drvdata->pm_runtime)
-               pm_runtime_get_sync(sdmac->sdma->dev);
-
+       sdma_pm_clk_enable(sdmac->sdma, false, true);
        spin_lock_irqsave(&sdmac->vc.lock, flags);
 
        sdma_disable_channel(chan);
@@ -1378,10 +1388,7 @@ static int sdma_terminate_all(struct dma_chan *chan)
 
        spin_unlock_irqrestore(&sdmac->vc.lock, flags);
 
-       if (sdmac->sdma->drvdata->pm_runtime) {
-               pm_runtime_mark_last_busy(sdmac->sdma->dev);
-               pm_runtime_put_autosuspend(sdmac->sdma->dev);
-       }
+       sdma_pm_clk_enable(sdmac->sdma, false, false);
 
        return 0;
 }
@@ -1778,9 +1785,7 @@ static void sdma_free_chan_resources(struct dma_chan 
*chan)
        if (unlikely(!sdmac->sdma->fw_data))
                return;
 
-       if (sdmac->sdma->drvdata->pm_runtime)
-               pm_runtime_get_sync(sdmac->sdma->dev);
-
+       sdma_pm_clk_enable(sdmac->sdma, false, true);
        sdma_terminate_all(chan);
 
        sdma_channel_synchronize(chan);
@@ -1796,11 +1801,7 @@ static void sdma_free_chan_resources(struct dma_chan 
*chan)
 
        kfree(sdmac->audio_config);
        sdmac->audio_config = NULL;
-
-       if (sdmac->sdma->drvdata->pm_runtime) {
-               pm_runtime_mark_last_busy(sdmac->sdma->dev);
-               pm_runtime_put_autosuspend(sdmac->sdma->dev);
-       }
+       sdma_pm_clk_enable(sdmac->sdma, false, false);
 }
 
 static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac, @@ 
-1866,14 +1867,11 @@ static struct dma_async_tx_descriptor *sdma_prep_memcpy(
        dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.\n",
                &dma_src, &dma_dst, len, channel);
 
-       if (sdma->drvdata->pm_runtime)
-               pm_runtime_get_sync(sdmac->sdma->dev);
-
+       sdma_pm_clk_enable(sdmac->sdma, false, true);
        desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM,
                                        len / SDMA_BD_MAX_CNT + 1);
        if (!desc) {
-               if (sdma->drvdata->pm_runtime)
-                       pm_runtime_put_sync_suspend(sdmac->sdma->dev);
+               sdma_pm_clk_enable(sdmac->sdma, true, false);
                return NULL;
        }
 
@@ -1907,10 +1905,7 @@ static struct dma_async_tx_descriptor *sdma_prep_memcpy(
                bd->mode.status = param;
        } while (len);
 
-       if (sdmac->sdma->drvdata->pm_runtime) {
-               pm_runtime_mark_last_busy(sdmac->sdma->dev);
-               pm_runtime_put_autosuspend(sdmac->sdma->dev);
-       }
+       sdma_pm_clk_enable(sdmac->sdma, false, false);
 
        return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);  } @@ -1927,9 
+1922,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
        struct scatterlist *sg;
        struct sdma_desc *desc;
 
-       if (sdma->drvdata->pm_runtime)
-               pm_runtime_get_sync(sdmac->sdma->dev);
-
+       sdma_pm_clk_enable(sdmac->sdma, false, true);
        sdma_config_write(chan, &sdmac->slave_config, direction);
 
        desc = sdma_transfer_init(sdmac, direction, sg_len); @@ -1996,10 
+1989,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                bd->mode.status = param;
        }
 
-       if (sdmac->sdma->drvdata->pm_runtime) {
-               pm_runtime_mark_last_busy(sdmac->sdma->dev);
-               pm_runtime_put_autosuspend(sdmac->sdma->dev);
-       }
+       sdma_pm_clk_enable(sdmac->sdma, false, false);
 
        return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
 err_bd_out:
@@ -2007,8 +1997,8 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
        kfree(desc);
 err_out:
        sdmac->status = DMA_ERROR;
-       if (sdma->drvdata->pm_runtime)
-               pm_runtime_put_sync_suspend(sdmac->sdma->dev);
+       sdma_pm_clk_enable(sdmac->sdma, true, false);
+
        return NULL;
 }
 
@@ -2026,8 +2016,7 @@ static struct dma_async_tx_descriptor 
*sdma_prep_dma_cyclic(
 
        dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
 
-       if (sdma->drvdata->pm_runtime)
-               pm_runtime_get_sync(sdmac->sdma->dev);
+       sdma_pm_clk_enable(sdmac->sdma, false, true);
 
        if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
                num_periods = buf_len / period_len;
@@ -2083,10 +2072,7 @@ static struct dma_async_tx_descriptor 
*sdma_prep_dma_cyclic(
                i++;
        }
 
-       if (sdmac->sdma->drvdata->pm_runtime) {
-               pm_runtime_mark_last_busy(sdmac->sdma->dev);
-               pm_runtime_put_autosuspend(sdmac->sdma->dev);
-       }
+       sdma_pm_clk_enable(sdmac->sdma, false, false);
 
        return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
 err_bd_out:
@@ -2094,8 +2080,8 @@ static struct dma_async_tx_descriptor 
*sdma_prep_dma_cyclic(
        kfree(desc);
 err_out:
        sdmac->status = DMA_ERROR;
-       if (sdma->drvdata->pm_runtime)
-               pm_runtime_put_sync_suspend(sdmac->sdma->dev);
+       sdma_pm_clk_enable(sdmac->sdma, true, false);
+
        return NULL;
 }
 
@@ -2213,19 +2199,14 @@ static void sdma_issue_pending(struct dma_chan *chan)
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        unsigned long flags;
 
-       if (sdmac->sdma->drvdata->pm_runtime)
-               pm_runtime_get_sync(sdmac->sdma->dev);
+       sdma_pm_clk_enable(sdmac->sdma, false, true);
 
        spin_lock_irqsave(&sdmac->vc.lock, flags);
        if (vchan_issue_pending(&sdmac->vc) && !sdmac->desc)
                sdma_start_desc(sdmac);
        spin_unlock_irqrestore(&sdmac->vc.lock, flags);
 
-       if (sdmac->sdma->drvdata->pm_runtime) {
-               pm_runtime_mark_last_busy(sdmac->sdma->dev);
-               pm_runtime_put_autosuspend(sdmac->sdma->dev);
-       }
-
+       sdma_pm_clk_enable(sdmac->sdma, false, false);
 }
 
 static void sdma_load_firmware(const struct firmware *fw, void *context)
--
2.25.1

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#11887): 
https://lists.yoctoproject.org/g/linux-yocto/message/11887
Mute This Topic: https://lists.yoctoproject.org/mt/95036683/21656
Group Owner: [email protected]
Unsubscribe: https://lists.yoctoproject.org/g/linux-yocto/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to