public inbox for devicetree@vger.kernel.org
 help / color / mirror / Atom feed
From: Shun-Chih.Yu <shun-chih.yu@mediatek.com>
To: Sean Wang <sean.wang@kernel.org>
Cc: devicetree@vger.kernel.org, Sean Wang <sean.wang@mediatek.com>,
	linux-kernel@vger.kernel.org, srv_wsdupstream@mediatek.com,
	Matthias Brugger <matthias.bgg@gmail.com>,
	Vinod Koul <vkoul@kernel.org>, Rob Herring <robh+dt@kernel.org>,
	linux-mediatek@lists.infradead.org, dmaengine@vger.kernel.org,
	Dan Williams <dan.j.williams@intel.com>,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 2/2] dmaengine: mediatek-cqdma: remove redundant queue structure
Date: Wed, 30 Jan 2019 17:37:54 +0800	[thread overview]
Message-ID: <1548841074.19418.13.camel@mtkswgap22> (raw)
In-Reply-To: <CAGp9LzpA6QmEx=ZP3N8oKF3zRd+pBj_YKi9G-rfC6kGCyTUcNA@mail.gmail.com>

On Thu, 2019-01-24 at 20:19 -0800, Sean Wang wrote:
> On Thu, Jan 24, 2019 at 2:46 AM <shun-chih.yu@mediatek.com> wrote:
> >
> > From: Shun-Chih Yu <shun-chih.yu@mediatek.com>
> >
> > This patch introduces active_vdec to indicate the virtual descriptor
> > under processing by the CQDMA dmaengine, and simplify the control logic
> > by removing redundant queue structure, tasklets, and completion
> > management.
> >
> > Also, wrong residue assignment in mtk_cqdma_tx_status and typos are
> > fixed.
> 
> overall changes are good and let code become clear, but it's better to
> do one thing at a patch instead of mixing all stuff together.
> 
Got it, I would separate this patch.
> >
> > Signed-off-by: Shun-Chih Yu <shun-chih.yu@mediatek.com>
> > ---
> >  drivers/dma/mediatek/mtk-cqdma.c |  399 ++++++++++----------------------------
> >  1 file changed, 98 insertions(+), 301 deletions(-)
> >
> > diff --git a/drivers/dma/mediatek/mtk-cqdma.c b/drivers/dma/mediatek/mtk-cqdma.c
> > index 131f397..387781b 100644
> > --- a/drivers/dma/mediatek/mtk-cqdma.c
> > +++ b/drivers/dma/mediatek/mtk-cqdma.c
> > @@ -22,6 +22,7 @@
> >  #include <linux/of_dma.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/pm_runtime.h>
> > +#include <linux/preempt.h>
> >  #include <linux/refcount.h>
> >  #include <linux/slab.h>
> >
> > @@ -47,7 +48,6 @@
> >  #define MTK_CQDMA_SRC                  0x1c
> >  #define MTK_CQDMA_DST                  0x20
> >  #define MTK_CQDMA_LEN1                 0x24
> > -#define MTK_CQDMA_LEN2                 0x28
> >  #define MTK_CQDMA_SRC2                 0x60
> >  #define MTK_CQDMA_DST2                 0x64
> >
> > @@ -69,45 +69,32 @@
> >   *                         descriptor (CVD)
> >   * @vd:                    An instance for struct virt_dma_desc
> >   * @len:                   The total data size device wants to move
> > - * @residue:               The remaining data size device will move
> >   * @dest:                  The destination address device wants to move to
> >   * @src:                   The source address device wants to move from
> >   * @ch:                    The pointer to the corresponding dma channel
> > - * @node:                  The lise_head struct to build link-list for VDs
> > - * @parent:                The pointer to the parent CVD
> >   */
> >  struct mtk_cqdma_vdesc {
> >         struct virt_dma_desc vd;
> >         size_t len;
> > -       size_t residue;
> >         dma_addr_t dest;
> >         dma_addr_t src;
> >         struct dma_chan *ch;
> > -
> > -       struct list_head node;
> > -       struct mtk_cqdma_vdesc *parent;
> >  };
> >
> >  /**
> >   * struct mtk_cqdma_pchan - The struct holding info describing physical
> >   *                         channel (PC)
> > - * @queue:                 Queue for the PDs issued to this PC
> > + * @active_vdesc:          The pointer to the CVD which is under processing
> >   * @base:                  The mapped register I/O base of this PC
> >   * @irq:                   The IRQ that this PC are using
> >   * @refcnt:                Track how many VCs are using this PC
> > - * @tasklet:               Tasklet for this PC
> >   * @lock:                  Lock protect agaisting multiple VCs access PC
> >   */
> >  struct mtk_cqdma_pchan {
> > -       struct list_head queue;
> > +       struct mtk_cqdma_vdesc *active_vdesc;
> >         void __iomem *base;
> >         u32 irq;
> > -
> >         refcount_t refcnt;
> > -
> > -       struct tasklet_struct tasklet;
> > -
> > -       /* lock to protect PC */
> >         spinlock_t lock;
> >  };
> >
> > @@ -116,14 +103,10 @@ struct mtk_cqdma_pchan {
> >   *                         channel (VC)
> >   * @vc:                    An instance for struct virt_dma_chan
> >   * @pc:                    The pointer to the underlying PC
> > - * @issue_completion:     The wait for all issued descriptors completited
> > - * @issue_synchronize:    Bool indicating channel synchronization starts
> >   */
> >  struct mtk_cqdma_vchan {
> >         struct virt_dma_chan vc;
> >         struct mtk_cqdma_pchan *pc;
> > -       struct completion issue_completion;
> > -       bool issue_synchronize;
> >  };
> >
> >  /**
> > @@ -168,7 +151,7 @@ static struct device *cqdma2dev(struct mtk_cqdma_device *cqdma)
> >
> >  static u32 mtk_dma_read(struct mtk_cqdma_pchan *pc, u32 reg)
> >  {
> > -       return readl(pc->base + reg);
> > +       return readl_relaxed(pc->base + reg);
> 
> that can be moved to separate patch and explains why
> 
Sure, I would separate this.

> >  }
> >
> >  static void mtk_dma_write(struct mtk_cqdma_pchan *pc, u32 reg, u32 val)
> > @@ -202,22 +185,22 @@ static void mtk_cqdma_vdesc_free(struct virt_dma_desc *vd)
> >         kfree(to_cqdma_vdesc(vd));
> >  }
> >
> > -static int mtk_cqdma_poll_engine_done(struct mtk_cqdma_pchan *pc, bool atomic)
> > +static int mtk_cqdma_poll_engine_done(struct mtk_cqdma_pchan *pc)
> >  {
> >         u32 status = 0;
> >
> > -       if (!atomic)
> > +       if (!in_task())
> 
> if (in_task())
> 
This would be fixed in the next revision.
> >                 return readl_poll_timeout(pc->base + MTK_CQDMA_EN,
> >                                           status,
> >                                           !(status & MTK_CQDMA_EN_BIT),
> >                                           MTK_CQDMA_USEC_POLL,
> >                                           MTK_CQDMA_TIMEOUT_POLL);
> > -
> > -       return readl_poll_timeout_atomic(pc->base + MTK_CQDMA_EN,
> > -                                        status,
> > -                                        !(status & MTK_CQDMA_EN_BIT),
> > -                                        MTK_CQDMA_USEC_POLL,
> > -                                        MTK_CQDMA_TIMEOUT_POLL);
> > +       else
> > +               return readl_poll_timeout_atomic(pc->base + MTK_CQDMA_EN,
> > +                                                status,
> > +                                                !(status & MTK_CQDMA_EN_BIT),
> > +                                                MTK_CQDMA_USEC_POLL,
> > +                                                MTK_CQDMA_TIMEOUT_POLL);
> >  }
> >
> >  static int mtk_cqdma_hard_reset(struct mtk_cqdma_pchan *pc)
> > @@ -225,20 +208,17 @@ static int mtk_cqdma_hard_reset(struct mtk_cqdma_pchan *pc)
> >         mtk_dma_set(pc, MTK_CQDMA_RESET, MTK_CQDMA_HARD_RST_BIT);
> >         mtk_dma_clr(pc, MTK_CQDMA_RESET, MTK_CQDMA_HARD_RST_BIT);
> >
> > -       return mtk_cqdma_poll_engine_done(pc, false);
> > +       return mtk_cqdma_poll_engine_done(pc);
> >  }
> >
> >  static void mtk_cqdma_start(struct mtk_cqdma_pchan *pc,
> >                             struct mtk_cqdma_vdesc *cvd)
> >  {
> > -       /* wait for the previous transaction done */
> > -       if (mtk_cqdma_poll_engine_done(pc, true) < 0)
> > -               dev_err(cqdma2dev(to_cqdma_dev(cvd->ch)), "cqdma wait transaction timeout\n");
> > -
> >         /* warm reset the dma engine for the new transaction */
> >         mtk_dma_set(pc, MTK_CQDMA_RESET, MTK_CQDMA_WARM_RST_BIT);
> > -       if (mtk_cqdma_poll_engine_done(pc, true) < 0)
> > -               dev_err(cqdma2dev(to_cqdma_dev(cvd->ch)), "cqdma warm reset timeout\n");
> > +       if (mtk_cqdma_poll_engine_done(pc) < 0)
> > +               dev_err(cqdma2dev(to_cqdma_dev(cvd->ch)),
> > +                       "cqdma warm reset timeout\n");
> >
> >         /* setup the source */
> >         mtk_dma_set(pc, MTK_CQDMA_SRC, cvd->src & MTK_CQDMA_ADDR_LIMIT);
> > @@ -253,11 +233,12 @@ static void mtk_cqdma_start(struct mtk_cqdma_pchan *pc,
> >  #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
> >         mtk_dma_set(pc, MTK_CQDMA_DST2, cvd->dest >> MTK_CQDMA_ADDR2_SHFIT);
> >  #else
> > -       mtk_dma_set(pc, MTK_CQDMA_SRC2, 0);
> > +       mtk_dma_set(pc, MTK_CQDMA_DST2, 0);
> 
> if it is mistakenly coded, it should be moved to separate fixup patch
> with a tag  Fixes: b1f01e48df5a ("dmaengine: mediatek: Add MediaTek
> Command-Queue DMA controller for MT6765 SoC")
Sure,I would separate this fixup.

> >  #endif
> >
> >         /* setup the length */
> > -       mtk_dma_set(pc, MTK_CQDMA_LEN1, cvd->len);
> > +       mtk_dma_set(pc, MTK_CQDMA_LEN1, (cvd->len < MTK_CQDMA_MAX_LEN) ?
> > +                   cvd->len : MTK_CQDMA_MAX_LEN);
> >
> >         /* start dma engine */
> >         mtk_dma_set(pc, MTK_CQDMA_EN, MTK_CQDMA_EN_BIT);
> > @@ -265,30 +246,17 @@ static void mtk_cqdma_start(struct mtk_cqdma_pchan *pc,
> >
> >  static void mtk_cqdma_issue_vchan_pending(struct mtk_cqdma_vchan *cvc)
> >  {
> > -       struct virt_dma_desc *vd, *vd2;
> > +       struct virt_dma_desc *vd;
> >         struct mtk_cqdma_pchan *pc = cvc->pc;
> > -       struct mtk_cqdma_vdesc *cvd;
> > -       bool trigger_engine = false;
> >
> >         lockdep_assert_held(&cvc->vc.lock);
> >         lockdep_assert_held(&pc->lock);
> >
> > -       list_for_each_entry_safe(vd, vd2, &cvc->vc.desc_issued, node) {
> > -               /* need to trigger dma engine if PC's queue is empty */
> > -               if (list_empty(&pc->queue))
> > -                       trigger_engine = true;
> > -
> > -               cvd = to_cqdma_vdesc(vd);
> > +       vd = vchan_next_desc(&cvc->vc);
> >
> > -               /* add VD into PC's queue */
> > -               list_add_tail(&cvd->node, &pc->queue);
> > -
> > -               /* start the dma engine */
> > -               if (trigger_engine)
> > -                       mtk_cqdma_start(pc, cvd);
> > -
> > -               /* remove VD from list desc_issued */
> > -               list_del(&vd->node);
> > +       if (vd && !pc->active_vdesc) {
> > +               pc->active_vdesc = to_cqdma_vdesc(vd);
> > +               mtk_cqdma_start(pc, pc->active_vdesc);
> >         }
> >  }
> >
> > @@ -298,100 +266,55 @@ static void mtk_cqdma_issue_vchan_pending(struct mtk_cqdma_vchan *cvc)
> >   */
> >  static bool mtk_cqdma_is_vchan_active(struct mtk_cqdma_vchan *cvc)
> >  {
> > -       struct mtk_cqdma_vdesc *cvd;
> > -
> > -       list_for_each_entry(cvd, &cvc->pc->queue, node)
> > -               if (cvc == to_cqdma_vchan(cvd->ch))
> > -                       return true;
> > -
> > -       return false;
> > +       return (!cvc->pc->active_vdesc) ? false :
> > +              (cvc == to_cqdma_vchan(cvc->pc->active_vdesc->ch));
> >  }
> >
> > -/*
> > - * return the pointer of the CVD that is just consumed by the PC
> > - */
> > -static struct mtk_cqdma_vdesc
> > -*mtk_cqdma_consume_work_queue(struct mtk_cqdma_pchan *pc)
> > +static void mtk_cqdma_complete_vdesc(struct mtk_cqdma_pchan *pc)
> >  {
> >         struct mtk_cqdma_vchan *cvc;
> > -       struct mtk_cqdma_vdesc *cvd, *ret = NULL;
> > -
> > -       /* consume a CVD from PC's queue */
> > -       cvd = list_first_entry_or_null(&pc->queue,
> > -                                      struct mtk_cqdma_vdesc, node);
> > -       if (unlikely(!cvd || !cvd->parent))
> > -               return NULL;
> > +       struct mtk_cqdma_vdesc *cvd;
> > +       struct virt_dma_desc *vd;
> > +       size_t tlen;
> >
> > +       cvd = pc->active_vdesc;
> >         cvc = to_cqdma_vchan(cvd->ch);
> > -       ret = cvd;
> > -
> > -       /* update residue of the parent CVD */
> > -       cvd->parent->residue -= cvd->len;
> >
> > -       /* delete CVD from PC's queue */
> > -       list_del(&cvd->node);
> > +       tlen = (cvd->len < MTK_CQDMA_MAX_LEN) ? cvd->len : MTK_CQDMA_MAX_LEN;
> > +       cvd->len -= tlen;
> > +       cvd->src += tlen;
> > +       cvd->dest += tlen;
> >
> >         spin_lock(&cvc->vc.lock);
> >
> > -       /* check whether all the child CVDs completed */
> > -       if (!cvd->parent->residue) {
> > -               /* add the parent VD into list desc_completed */
> > -               vchan_cookie_complete(&cvd->parent->vd);
> > -
> > -               /* setup completion if this VC is under synchronization */
> > -               if (cvc->issue_synchronize && !mtk_cqdma_is_vchan_active(cvc)) {
> > -                       complete(&cvc->issue_completion);
> > -                       cvc->issue_synchronize = false;
> > -               }
> > -       }
> > -
> > -       spin_unlock(&cvc->vc.lock);
> > -
> > -       /* start transaction for next CVD in the queue */
> > -       cvd = list_first_entry_or_null(&pc->queue,
> > -                                      struct mtk_cqdma_vdesc, node);
> > -       if (cvd)
> > -               mtk_cqdma_start(pc, cvd);
> > +       /* check whether the VD completed */
> > +       if (!cvd->len) {
> > +               /* delete VD from desc_issued */
> > +               list_del(&cvd->vd.node);
> >
> > -       return ret;
> > -}
> > -
> > -static void mtk_cqdma_tasklet_cb(unsigned long data)
> > -{
> > -       struct mtk_cqdma_pchan *pc = (struct mtk_cqdma_pchan *)data;
> > -       struct mtk_cqdma_vdesc *cvd = NULL;
> > -       unsigned long flags;
> > +               /* add the VD into list desc_completed */
> > +               vchan_cookie_complete(&cvd->vd);
> >
> > -       spin_lock_irqsave(&pc->lock, flags);
> > -       /* consume the queue */
> > -       cvd = mtk_cqdma_consume_work_queue(pc);
> > -       spin_unlock_irqrestore(&pc->lock, flags);
> > -
> > -       /* submit the next CVD */
> > -       if (cvd) {
> > -               dma_run_dependencies(&cvd->vd.tx);
> > -
> > -               /*
> > -                * free child CVD after completion.
> > -                * the parent CVD would be freeed with desc_free by user.
> > -                */
> > -               if (cvd->parent != cvd)
> > -                       kfree(cvd);
> > +               /* get the next active VD */
> > +               vd = vchan_next_desc(&cvc->vc);
> > +               pc->active_vdesc = (!vd) ? NULL : to_cqdma_vdesc(vd);
> >         }
> >
> > -       /* re-enable interrupt before leaving tasklet */
> > -       enable_irq(pc->irq);
> > +       /* start the next transaction */
> > +       if (pc->active_vdesc)
> > +               mtk_cqdma_start(pc, pc->active_vdesc);
> > +
> > +       spin_unlock(&cvc->vc.lock);
> >  }
> >
> >  static irqreturn_t mtk_cqdma_irq(int irq, void *devid)
> >  {
> >         struct mtk_cqdma_device *cqdma = devid;
> >         irqreturn_t ret = IRQ_NONE;
> > -       bool schedule_tasklet = false;
> >         u32 i;
> >
> >         /* clear interrupt flags for each PC */
> > -       for (i = 0; i < cqdma->dma_channels; ++i, schedule_tasklet = false) {
> > +       for (i = 0; i < cqdma->dma_channels; ++i) {
> >                 spin_lock(&cqdma->pc[i]->lock);
> >                 if (mtk_dma_read(cqdma->pc[i],
> >                                  MTK_CQDMA_INT_FLAG) & MTK_CQDMA_INT_FLAG_BIT) {
> > @@ -399,72 +322,21 @@ static irqreturn_t mtk_cqdma_irq(int irq, void *devid)
> >                         mtk_dma_clr(cqdma->pc[i], MTK_CQDMA_INT_FLAG,
> >                                     MTK_CQDMA_INT_FLAG_BIT);
> >
> > -                       schedule_tasklet = true;
> > +                       mtk_cqdma_complete_vdesc(cqdma->pc[i]);
> > +
> >                         ret = IRQ_HANDLED;
> >                 }
> >                 spin_unlock(&cqdma->pc[i]->lock);
> > -
> > -               if (schedule_tasklet) {
> > -                       /* disable interrupt */
> > -                       disable_irq_nosync(cqdma->pc[i]->irq);
> > -
> > -                       /* schedule the tasklet to handle the transactions */
> > -                       tasklet_schedule(&cqdma->pc[i]->tasklet);
> > -               }
> >         }
> >
> >         return ret;
> >  }
> >
> > -static struct virt_dma_desc *mtk_cqdma_find_active_desc(struct dma_chan *c,
> > -                                                       dma_cookie_t cookie)
> > -{
> > -       struct mtk_cqdma_vchan *cvc = to_cqdma_vchan(c);
> > -       struct virt_dma_desc *vd;
> > -       unsigned long flags;
> > -
> > -       spin_lock_irqsave(&cvc->pc->lock, flags);
> > -       list_for_each_entry(vd, &cvc->pc->queue, node)
> > -               if (vd->tx.cookie == cookie) {
> > -                       spin_unlock_irqrestore(&cvc->pc->lock, flags);
> > -                       return vd;
> > -               }
> > -       spin_unlock_irqrestore(&cvc->pc->lock, flags);
> > -
> > -       list_for_each_entry(vd, &cvc->vc.desc_issued, node)
> > -               if (vd->tx.cookie == cookie)
> > -                       return vd;
> > -
> > -       return NULL;
> > -}
> > -
> >  static enum dma_status mtk_cqdma_tx_status(struct dma_chan *c,
> >                                            dma_cookie_t cookie,
> >                                            struct dma_tx_state *txstate)
> >  {
> > -       struct mtk_cqdma_vchan *cvc = to_cqdma_vchan(c);
> > -       struct mtk_cqdma_vdesc *cvd;
> > -       struct virt_dma_desc *vd;
> > -       enum dma_status ret;
> > -       unsigned long flags;
> > -       size_t bytes = 0;
> > -
> > -       ret = dma_cookie_status(c, cookie, txstate);
> > -       if (ret == DMA_COMPLETE || !txstate)
> > -               return ret;
> > -
> > -       spin_lock_irqsave(&cvc->vc.lock, flags);
> > -       vd = mtk_cqdma_find_active_desc(c, cookie);
> > -       spin_unlock_irqrestore(&cvc->vc.lock, flags);
> > -
> > -       if (vd) {
> > -               cvd = to_cqdma_vdesc(vd);
> > -               bytes = cvd->residue;
> > -       }
> > -
> > -       dma_set_residue(txstate, bytes);
> > -
> > -       return ret;
> > +       return dma_cookie_status(c, cookie, txstate);
> >  }
> >
> >  static void mtk_cqdma_issue_pending(struct dma_chan *c)
> > @@ -473,7 +345,7 @@ static void mtk_cqdma_issue_pending(struct dma_chan *c)
> >         unsigned long pc_flags;
> >         unsigned long vc_flags;
> >
> > -       /* acquire PC's lock before VS's lock for lock dependency in tasklet */
> > +       /* acquire PC's lock before VC's lock for lock dependency in ISR */
> >         spin_lock_irqsave(&cvc->pc->lock, pc_flags);
> >         spin_lock_irqsave(&cvc->vc.lock, vc_flags);
> >
> > @@ -488,124 +360,56 @@ static void mtk_cqdma_issue_pending(struct dma_chan *c)
> >  mtk_cqdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest,
> >                           dma_addr_t src, size_t len, unsigned long flags)
> >  {
> > -       struct mtk_cqdma_vdesc **cvd;
> > -       struct dma_async_tx_descriptor *tx = NULL, *prev_tx = NULL;
> > -       size_t i, tlen, nr_vd;
> > -
> > -       /*
> > -        * In the case that trsanction length is larger than the
> > -        * DMA engine supports, a single memcpy transaction needs
> > -        * to be separated into several DMA transactions.
> > -        * Each DMA transaction would be described by a CVD,
> > -        * and the first one is referred as the parent CVD,
> > -        * while the others are child CVDs.
> > -        * The parent CVD's tx descriptor is the only tx descriptor
> > -        * returned to the DMA user, and it should not be completed
> > -        * until all the child CVDs completed.
> > -        */
> > -       nr_vd = DIV_ROUND_UP(len, MTK_CQDMA_MAX_LEN);
> > -       cvd = kcalloc(nr_vd, sizeof(*cvd), GFP_NOWAIT);
> > +       struct mtk_cqdma_vdesc *cvd;
> > +
> > +       cvd = kzalloc(sizeof(*cvd), GFP_NOWAIT);
> >         if (!cvd)
> >                 return NULL;
> >
> > -       for (i = 0; i < nr_vd; ++i) {
> > -               cvd[i] = kzalloc(sizeof(*cvd[i]), GFP_NOWAIT);
> > -               if (!cvd[i]) {
> > -                       for (; i > 0; --i)
> > -                               kfree(cvd[i - 1]);
> > -                       return NULL;
> > -               }
> > +       /* setup dma channel */
> > +       cvd->ch = c;
> >
> > -               /* setup dma channel */
> > -               cvd[i]->ch = c;
> > +       /* setup sourece, destination, and length */
> > +       cvd->len = len;
> > +       cvd->src = src;
> > +       cvd->dest = dest;
> >
> > -               /* setup sourece, destination, and length */
> > -               tlen = (len > MTK_CQDMA_MAX_LEN) ? MTK_CQDMA_MAX_LEN : len;
> > -               cvd[i]->len = tlen;
> > -               cvd[i]->src = src;
> > -               cvd[i]->dest = dest;
> > -
> > -               /* setup tx descriptor */
> > -               tx = vchan_tx_prep(to_virt_chan(c), &cvd[i]->vd, flags);
> > -               tx->next = NULL;
> > -
> > -               if (!i) {
> > -                       cvd[0]->residue = len;
> > -               } else {
> > -                       prev_tx->next = tx;
> > -                       cvd[i]->residue = tlen;
> > -               }
> > -
> > -               cvd[i]->parent = cvd[0];
> > -
> > -               /* update the src, dest, len, prev_tx for the next CVD */
> > -               src += tlen;
> > -               dest += tlen;
> > -               len -= tlen;
> > -               prev_tx = tx;
> > -       }
> > -
> > -       return &cvd[0]->vd.tx;
> > +       return vchan_tx_prep(to_virt_chan(c), &cvd->vd, flags);
> >  }
> >
> > -static void mtk_cqdma_free_inactive_desc(struct dma_chan *c)
> > -{
> > -       struct virt_dma_chan *vc = to_virt_chan(c);
> > -       unsigned long flags;
> > -       LIST_HEAD(head);
> > -
> > -       /*
> > -        * set desc_allocated, desc_submitted,
> > -        * and desc_issued as the candicates to be freed
> > -        */
> > -       spin_lock_irqsave(&vc->lock, flags);
> > -       list_splice_tail_init(&vc->desc_allocated, &head);
> > -       list_splice_tail_init(&vc->desc_submitted, &head);
> > -       list_splice_tail_init(&vc->desc_issued, &head);
> > -       spin_unlock_irqrestore(&vc->lock, flags);
> > -
> > -       /* free descriptor lists */
> > -       vchan_dma_desc_free_list(vc, &head);
> > -}
> > -
> > -static void mtk_cqdma_free_active_desc(struct dma_chan *c)
> > +static int mtk_cqdma_terminate_all(struct dma_chan *c)
> >  {
> >         struct mtk_cqdma_vchan *cvc = to_cqdma_vchan(c);
> > -       bool sync_needed = false;
> > +       struct virt_dma_chan *vc = to_virt_chan(c);
> >         unsigned long pc_flags;
> >         unsigned long vc_flags;
> > +       LIST_HEAD(head);
> >
> > -       /* acquire PC's lock first due to lock dependency in dma ISR */
> > -       spin_lock_irqsave(&cvc->pc->lock, pc_flags);
> > -       spin_lock_irqsave(&cvc->vc.lock, vc_flags);
> > -
> > -       /* synchronization is required if this VC is active */
> > -       if (mtk_cqdma_is_vchan_active(cvc)) {
> > -               cvc->issue_synchronize = true;
> > -               sync_needed = true;
> > -       }
> > +       do {
> > +               /* acquire PC's lock first due to lock dependency in dma ISR */
> > +               spin_lock_irqsave(&cvc->pc->lock, pc_flags);
> > +               spin_lock_irqsave(&cvc->vc.lock, vc_flags);
> >
> > -       spin_unlock_irqrestore(&cvc->vc.lock, vc_flags);
> > -       spin_unlock_irqrestore(&cvc->pc->lock, pc_flags);
> > +               /* wait for the VC to be inactive  */
> > +               if (mtk_cqdma_is_vchan_active(cvc)) {
> > +                       spin_unlock_irqrestore(&cvc->vc.lock, vc_flags);
> > +                       spin_unlock_irqrestore(&cvc->pc->lock, pc_flags);
> > +                       continue;
> > +               }
> >
> > -       /* waiting for the completion of this VC */
> > -       if (sync_needed)
> > -               wait_for_completion(&cvc->issue_completion);
> > +               /* get VDs from lists */
> > +               vchan_get_all_descriptors(vc, &head);
> >
> > -       /* free all descriptors in list desc_completed */
> > -       vchan_synchronize(&cvc->vc);
> > +               /* free all the VDs */
> > +               vchan_dma_desc_free_list(vc, &head);
> >
> > -       WARN_ONCE(!list_empty(&cvc->vc.desc_completed),
> > -                 "Desc pending still in list desc_completed\n");
> > -}
> > +               spin_unlock_irqrestore(&cvc->vc.lock, vc_flags);
> > +               spin_unlock_irqrestore(&cvc->pc->lock, pc_flags);
> >
> > -static int mtk_cqdma_terminate_all(struct dma_chan *c)
> > -{
> > -       /* free descriptors not processed yet by hardware */
> > -       mtk_cqdma_free_inactive_desc(c);
> > +               break;
> > +       } while (1);
> 
> use wait_for_completion_timeout or something like that instead of
> polling here to reduce cpu computing waste and to avoid dead-loop risk

Sure, I would drop the infinite polling to make this loop more robust.
> >
> > -       /* free descriptors being processed by hardware */
> > -       mtk_cqdma_free_active_desc(c);
> > +       vchan_synchronize(&cvc->vc);
> >
> >         return 0;
> >  }
> > @@ -618,7 +422,7 @@ static int mtk_cqdma_alloc_chan_resources(struct dma_chan *c)
> >         u32 i, min_refcnt = U32_MAX, refcnt;
> >         unsigned long flags;
> >
> > -       /* allocate PC with the minimun refcount */
> > +       /* allocate PC with the minimum refcount */
> >         for (i = 0; i < cqdma->dma_channels; ++i) {
> >                 refcnt = refcount_read(&cqdma->pc[i]->refcnt);
> >                 if (refcnt < min_refcnt) {
> > @@ -671,8 +475,9 @@ static void mtk_cqdma_free_chan_resources(struct dma_chan *c)
> >                 mtk_dma_set(cvc->pc, MTK_CQDMA_FLUSH, MTK_CQDMA_FLUSH_BIT);
> >
> >                 /* wait for the completion of flush operation */
> > -               if (mtk_cqdma_poll_engine_done(cvc->pc, false) < 0)
> > -                       dev_err(cqdma2dev(to_cqdma_dev(c)), "cqdma flush timeout\n");
> > +               if (mtk_cqdma_poll_engine_done(cvc->pc) < 0)
> > +                       dev_err(cqdma2dev(to_cqdma_dev(c)),
> > +                               "cqdma flush timeout\n");
> >
> >                 /* clear the flush bit and interrupt flag */
> >                 mtk_dma_clr(cvc->pc, MTK_CQDMA_FLUSH, MTK_CQDMA_FLUSH_BIT);
> > @@ -787,9 +592,9 @@ static int mtk_cqdma_probe(struct platform_device *pdev)
> >         if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node,
> >                                                       "dma-requests",
> >                                                       &cqdma->dma_requests)) {
> > -               dev_info(&pdev->dev,
> > -                        "Using %u as missing dma-requests property\n",
> > -                        MTK_CQDMA_NR_VCHANS);
> > +               dev_dbg(&pdev->dev,
> > +                       "Using %u as missing dma-requests property\n",
> > +                       MTK_CQDMA_NR_VCHANS);
> >
> >                 cqdma->dma_requests = MTK_CQDMA_NR_VCHANS;
> >         }
> > @@ -797,9 +602,9 @@ static int mtk_cqdma_probe(struct platform_device *pdev)
> >         if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node,
> >                                                       "dma-channels",
> >                                                       &cqdma->dma_channels)) {
> > -               dev_info(&pdev->dev,
> > -                        "Using %u as missing dma-channels property\n",
> > -                        MTK_CQDMA_NR_PCHANS);
> > +               dev_dbg(&pdev->dev,
> > +                       "Using %u as missing dma-channels property\n",
> > +                       MTK_CQDMA_NR_PCHANS);
> >
> >                 cqdma->dma_channels = MTK_CQDMA_NR_PCHANS;
> >         }
> > @@ -816,7 +621,7 @@ static int mtk_cqdma_probe(struct platform_device *pdev)
> >                 if (!cqdma->pc[i])
> >                         return -ENOMEM;
> >
> > -               INIT_LIST_HEAD(&cqdma->pc[i]->queue);
> > +               cqdma->pc[i]->active_vdesc = NULL;
> >                 spin_lock_init(&cqdma->pc[i]->lock);
> >                 refcount_set(&cqdma->pc[i]->refcnt, 0);
> >
> > @@ -860,7 +665,6 @@ static int mtk_cqdma_probe(struct platform_device *pdev)
> >                 vc = &cqdma->vc[i];
> >                 vc->vc.desc_free = mtk_cqdma_vdesc_free;
> >                 vchan_init(&vc->vc, dd);
> > -               init_completion(&vc->issue_completion);
> >         }
> >
> >         err = dma_async_device_register(dd);
> > @@ -884,12 +688,7 @@ static int mtk_cqdma_probe(struct platform_device *pdev)
> >
> >         platform_set_drvdata(pdev, cqdma);
> >
> > -       /* initialize tasklet for each PC */
> > -       for (i = 0; i < cqdma->dma_channels; ++i)
> > -               tasklet_init(&cqdma->pc[i]->tasklet, mtk_cqdma_tasklet_cb,
> > -                            (unsigned long)cqdma->pc[i]);
> > -
> > -       dev_info(&pdev->dev, "MediaTek CQDMA driver registered\n");
> > +       dev_dbg(&pdev->dev, "MediaTek CQDMA driver registered\n");
> >
> >         return 0;
> >
> > @@ -923,8 +722,6 @@ static int mtk_cqdma_remove(struct platform_device *pdev)
> >
> >                 /* Waits for any pending IRQ handlers to complete */
> >                 synchronize_irq(cqdma->pc[i]->irq);
> > -
> > -               tasklet_kill(&cqdma->pc[i]->tasklet);
> >         }
> >
> >         /* disable hardware */
> > --
> > 1.7.9.5
> >
> >
> > _______________________________________________
> > Linux-mediatek mailing list
> > Linux-mediatek@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-mediatek
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

      reply	other threads:[~2019-01-30  9:37 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-24 10:44 [PATCH] remove redundant queue structure for Mediatek Command-Queue DMA controller shun-chih.yu
2019-01-24 10:44 ` [PATCH 1/2] dt-bindings: dmaengine: Add MediaTek Command-Queue DMA controller bindings shun-chih.yu
2019-01-25  3:52   ` Sean Wang
2019-01-24 10:44 ` [PATCH 2/2] dmaengine: mediatek-cqdma: remove redundant queue structure shun-chih.yu
2019-01-25  4:19   ` Sean Wang
2019-01-30  9:37     ` Shun-Chih.Yu [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1548841074.19418.13.camel@mtkswgap22 \
    --to=shun-chih.yu@mediatek.com \
    --cc=dan.j.williams@intel.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dmaengine@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=matthias.bgg@gmail.com \
    --cc=robh+dt@kernel.org \
    --cc=sean.wang@kernel.org \
    --cc=sean.wang@mediatek.com \
    --cc=srv_wsdupstream@mediatek.com \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox