In current sf-pdma implementation, the channel resources's alloc and free
operations are controlled by sf_pdma_alloc_chan_resources() and
sf_pdma_free_chan_resources() functions respectively, while the channel related
done_tasklet and err_tasklet are controlled by sf_pdma_setup_chans() and
sf_pdma_remove(). And this design will cause the following issue, especially
in rt kernel:

  Unable to handle kernel NULL pointer dereference at virtual address 
0000000000000088
  Oops [#1]
  Modules linked in: openvswitch nsh nf_conncount nf_nat fuse nfnetlink
  CPU: 0 PID: 64 Comm: irq/19-3000000. Not tainted 
6.6.116-rt31-yocto-preempt-rt #1
  Hardware name: Microchip PolarFire-SoC Icicle Kit (DT)
  epc : sf_pdma_donebh_tasklet+0x52/0xe8
   ra : sf_pdma_donebh_tasklet+0x48/0xe8
  epc : ffffffff806ab8be ra : ffffffff806ab8b4 sp : ffffffc8002c3c40
   gp : ffffffff81e120c8 tp : ffffffe7a2ab4980 t0 : 0000000001329be0
   t1 : 0000000000000006 t2 : 0000000000004c08 s0 : ffffffc8002c3c60
   s1 : ffffffe7a207b390 a0 : ffffffff8121da90 a1 : 0000000000000030
   a2 : 0000000000000200 a3 : 0000000000000000 a4 : dead000000000000
   a5 : 0000000000000003 a6 : ffffffff81305bd0 a7 : ffffffff81c08080
   s2 : ffffffe7a207b298 s3 : 0000000000000001 s4 : ffffffff80e32640
   s5 : ffffffff81dd7b20 s6 : ffffffff81e522b8 s7 : fffffffffffffffd
   s8 : ffffffe7a207b398 s9 : 0000000000000000 s10: ffffffe7fef574d0
   s11: ffffffff81dd7b20 t3 : 000000000000031f t4 : 0000000000000000
   t5 : 00000000e0ccdeeb t6 : 0000000001329491
  status: 0000000200000120 badaddr: 0000000000000088 cause: 000000000000000d
  [<ffffffff806ab8be>] sf_pdma_donebh_tasklet+0x52/0xe8
  [<ffffffff800216c6>] tasklet_action_common.isra.0+0x168/0x352
  [<ffffffff8002190c>] tasklet_hi_action+0x2a/0x32
  [<ffffffff80021140>] handle_softirqs.isra.0+0x148/0x2fc
  [<ffffffff800214c0>] __local_bh_enable_ip+0x72/0xbc
  [<ffffffff800791ac>] irq_forced_thread_fn+0x6a/0x7a
  [<ffffffff80079028>] irq_thread+0x160/0x220
  [<ffffffff8003dde2>] kthread+0xda/0xf6
  [<ffffffff80bca256>] ret_from_fork+0xe/0x18
  Code: 854a c097 0051 80e7 d2a0 b683 f984 d737 fdea 1712 (66d0) 62cc
  ---[ end trace 0000000000000000 ]---
  Kernel panic - not syncing: Fatal exception in interrupt
  SMP: stopping secondary CPUs
  ---[ end Kernel panic - not syncing: Fatal exception in interrupt ]---

So this patch updates the following tasklet related items:
  1. move the setup/kill operations of done_tasklet and err_tasklet
     to sf_pdma_alloc/free_chan_resources()
  2. update sf_pdma_disable_request() by adding PDMA_ENABLE_DONE_INT_MASK and
     PDMA_ENABLE_ERR_INT_MASK bits setting to make it consistent with
     sf_pdma_enable_request()
  3. put sf_pdma_alloc/free_chan_resources() to a proper location to after the
     definitions of the done_tasklet and err_tasklet

Then the issue can be fixed.

Signed-off-by: Zhantao Tang <[email protected]>
---
 drivers/dma/sf-pdma/sf-pdma.c | 68 ++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 32 deletions(-)

diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c
index 4f982f65aeb16..b0dc5e0727063 100644
--- a/drivers/dma/sf-pdma/sf-pdma.c
+++ b/drivers/dma/sf-pdma/sf-pdma.c
@@ -118,38 +118,15 @@ static int sf_pdma_slave_config(struct dma_chan *dchan,
        return 0;
 }
 
-static int sf_pdma_alloc_chan_resources(struct dma_chan *dchan)
-{
-       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
-       struct pdma_regs *regs = &chan->regs;
-
-       dma_cookie_init(dchan);
-       writel(PDMA_CLAIM_MASK, regs->ctrl);
-
-       return 0;
-}
-
 static void sf_pdma_disable_request(struct sf_pdma_chan *chan)
 {
        struct pdma_regs *regs = &chan->regs;
 
-       writel(readl(regs->ctrl) & ~PDMA_RUN_MASK, regs->ctrl);
-}
-
-static void sf_pdma_free_chan_resources(struct dma_chan *dchan)
-{
-       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
-       unsigned long flags;
-       LIST_HEAD(head);
+       writel(readl(regs->ctrl) & ~(PDMA_RUN_MASK |
+                                    PDMA_ENABLE_DONE_INT_MASK |
+                                    PDMA_ENABLE_ERR_INT_MASK),
+              regs->ctrl);
 
-       spin_lock_irqsave(&chan->vchan.lock, flags);
-       sf_pdma_disable_request(chan);
-       kfree(chan->desc);
-       chan->desc = NULL;
-       vchan_get_all_descriptors(&chan->vchan, &head);
-       sf_pdma_disclaim_chan(chan);
-       spin_unlock_irqrestore(&chan->vchan.lock, flags);
-       vchan_dma_desc_free_list(&chan->vchan, &head);
 }
 
 static size_t sf_pdma_desc_residue(struct sf_pdma_chan *chan,
@@ -486,12 +463,41 @@ static void sf_pdma_setup_chans(struct sf_pdma *pdma)
                vchan_init(&chan->vchan, &pdma->dma_dev);
 
                writel(PDMA_CLEAR_CTRL, chan->regs.ctrl);
-
-               tasklet_setup(&chan->done_tasklet, sf_pdma_donebh_tasklet);
-               tasklet_setup(&chan->err_tasklet, sf_pdma_errbh_tasklet);
        }
 }
 
+static int sf_pdma_alloc_chan_resources(struct dma_chan *dchan)
+{
+       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
+       struct pdma_regs *regs = &chan->regs;
+
+       dma_cookie_init(dchan);
+       writel(PDMA_CLAIM_MASK, regs->ctrl);
+
+       tasklet_setup(&chan->done_tasklet, sf_pdma_donebh_tasklet);
+       tasklet_setup(&chan->err_tasklet, sf_pdma_errbh_tasklet);
+
+       return 0;
+}
+
+static void sf_pdma_free_chan_resources(struct dma_chan *dchan)
+{
+       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&chan->vchan.lock, flags);
+       sf_pdma_disable_request(chan);
+       tasklet_kill(&chan->done_tasklet);
+       tasklet_kill(&chan->err_tasklet);
+       kfree(chan->desc);
+       chan->desc = NULL;
+       vchan_get_all_descriptors(&chan->vchan, &head);
+       sf_pdma_disclaim_chan(chan);
+       spin_unlock_irqrestore(&chan->vchan.lock, flags);
+       vchan_dma_desc_free_list(&chan->vchan, &head);
+}
+
 static struct dma_chan *sf_pdma_of_xlate(struct of_phandle_args *dma_spec,
                                           struct of_dma *ofdma)
 {
@@ -630,8 +636,6 @@ static int sf_pdma_remove(struct platform_device *pdev)
                devm_free_irq(&pdev->dev, ch->errirq, ch);
                list_del(&ch->vchan.chan.device_node);
                tasklet_kill(&ch->vchan.task);
-               tasklet_kill(&ch->done_tasklet);
-               tasklet_kill(&ch->err_tasklet);
        }
 
        dma_async_device_unregister(&pdma->dma_dev);
-- 
2.34.1

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

Reply via email to