Merge tag 'dmaengine-fix-5.2-rc4' of git://git.infradead.org/users/vkoul/slave-dma
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 8 Jun 2019 19:46:31 +0000 (12:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 8 Jun 2019 19:46:31 +0000 (12:46 -0700)
Pull dmaengine fixes from Vinod Koul:

 - jz4780 transfer fix for acking descriptors early

 - fsl-qdma: clean registers on error

 - dw-axi-dmac: null pointer dereference fix

 - mediatek-cqdma: fix sleeping in atomic context

 - tegra210-adma: fix bunch os issues like crashing in driver probe,
   channel FIFO configuration etc.

 - sprd: Fixes for possible crash on descriptor status, block length
   overflow. For 2-stage transfer fix incorrect start, configuration and
   interrupt handling.

* tag 'dmaengine-fix-5.2-rc4' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: sprd: Add interrupt support for 2-stage transfer
  dmaengine: sprd: Fix the right place to configure 2-stage transfer
  dmaengine: sprd: Fix block length overflow
  dmaengine: sprd: Fix the incorrect start for 2-stage destination channels
  dmaengine: sprd: Add validation of current descriptor in irq handler
  dmaengine: sprd: Fix the possible crash when getting descriptor status
  dmaengine: tegra210-adma: Fix spelling
  dmaengine: tegra210-adma: Fix channel FIFO configuration
  dmaengine: tegra210-adma: Fix crash during probe
  dmaengine: mediatek-cqdma: sleeping in atomic context
  dmaengine: dw-axi-dmac: fix null dereference when pointer first is null
  dmaengine: fsl-qdma: Add improvement
  dmaengine: jz4780: Fix transfers being ACKed too soon

1  2 
drivers/dma/dma-jz4780.c
drivers/dma/tegra210-adma.c

diff --combined drivers/dma/dma-jz4780.c
index 7204fdeff6c5357d6d9ce516689e3b6468f1e7a0,f49534019d37dad9f1445c2693df1626df861e9c..263bee76ef0d4697106f6b73497abc51bc7388e6
@@@ -1,9 -1,13 +1,9 @@@
 +// SPDX-License-Identifier: GPL-2.0-or-later
  /*
   * Ingenic JZ4780 DMA controller
   *
   * Copyright (c) 2015 Imagination Technologies
   * Author: Alex Smith <alex@alex-smith.me.uk>
 - *
 - * This program is free software; you can redistribute it and/or modify it
 - * under the terms of the GNU General Public License as published by the
 - * Free Software Foundation;  either version 2 of the  License, or (at your
 - * option) any later version.
   */
  
  #include <linux/clk.h>
@@@ -662,10 -666,11 +662,11 @@@ static enum dma_status jz4780_dma_tx_st
        return status;
  }
  
- static void jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma,
-       struct jz4780_dma_chan *jzchan)
+ static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma,
+                               struct jz4780_dma_chan *jzchan)
  {
        uint32_t dcs;
+       bool ack = true;
  
        spin_lock(&jzchan->vchan.lock);
  
                if ((dcs & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT)) == 0) {
                        if (jzchan->desc->type == DMA_CYCLIC) {
                                vchan_cyclic_callback(&jzchan->desc->vdesc);
-                       } else {
+                               jz4780_dma_begin(jzchan);
+                       } else if (dcs & JZ_DMA_DCS_TT) {
                                vchan_cookie_complete(&jzchan->desc->vdesc);
                                jzchan->desc = NULL;
-                       }
  
-                       jz4780_dma_begin(jzchan);
+                               jz4780_dma_begin(jzchan);
+                       } else {
+                               /* False positive - continue the transfer */
+                               ack = false;
+                               jz4780_dma_chn_writel(jzdma, jzchan->id,
+                                                     JZ_DMA_REG_DCS,
+                                                     JZ_DMA_DCS_CTE);
+                       }
                }
        } else {
                dev_err(&jzchan->vchan.chan.dev->device,
        }
  
        spin_unlock(&jzchan->vchan.lock);
+       return ack;
  }
  
  static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
  {
        struct jz4780_dma_dev *jzdma = data;
+       unsigned int nb_channels = jzdma->soc_data->nb_channels;
        uint32_t pending, dmac;
        int i;
  
        pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP);
  
-       for (i = 0; i < jzdma->soc_data->nb_channels; i++) {
-               if (!(pending & (1<<i)))
-                       continue;
-               jz4780_dma_chan_irq(jzdma, &jzdma->chan[i]);
+       for_each_set_bit(i, (unsigned long *)&pending, nb_channels) {
+               if (jz4780_dma_chan_irq(jzdma, &jzdma->chan[i]))
+                       pending &= ~BIT(i);
        }
  
        /* Clear halt and address error status of all channels. */
        jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, dmac);
  
        /* Clear interrupt pending status. */
-       jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DIRQP, 0);
+       jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DIRQP, pending);
  
        return IRQ_HANDLED;
  }
index d51550dd91c761d44c1a7a650670f9923dc08f79,17ea4dd99c62c56bb12d51dc912165f8fbf219c8..2805853e963fcf6f9076e8360ebd519585efa94e
@@@ -1,8 -1,19 +1,8 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  /*
   * ADMA driver for Nvidia's Tegra210 ADMA controller.
   *
   * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
 - *
 - * This program is free software; you can redistribute it and/or modify it
 - * under the terms and conditions of the GNU General Public License,
 - * version 2, as published by the Free Software Foundation.
 - *
 - * This program is distributed in the hope it will be useful, but WITHOUT
 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 - * more details.
 - *
 - * You should have received a copy of the GNU General Public License
 - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  #include <linux/clk.h>
  #define ADMA_CH_CONFIG_MAX_BUFS                               8
  
  #define ADMA_CH_FIFO_CTRL                             0x2c
- #define ADMA_CH_FIFO_CTRL_OVRFW_THRES(val)            (((val) & 0xf) << 24)
- #define ADMA_CH_FIFO_CTRL_STARV_THRES(val)            (((val) & 0xf) << 16)
- #define ADMA_CH_FIFO_CTRL_TX_FIFO_SIZE_SHIFT          8
- #define ADMA_CH_FIFO_CTRL_RX_FIFO_SIZE_SHIFT          0
+ #define TEGRA210_ADMA_CH_FIFO_CTRL_OFLWTHRES(val)     (((val) & 0xf) << 24)
+ #define TEGRA210_ADMA_CH_FIFO_CTRL_STRVTHRES(val)     (((val) & 0xf) << 16)
+ #define TEGRA210_ADMA_CH_FIFO_CTRL_TXSIZE(val)                (((val) & 0xf) << 8)
+ #define TEGRA210_ADMA_CH_FIFO_CTRL_RXSIZE(val)                ((val) & 0xf)
+ #define TEGRA186_ADMA_CH_FIFO_CTRL_OFLWTHRES(val)     (((val) & 0x1f) << 24)
+ #define TEGRA186_ADMA_CH_FIFO_CTRL_STRVTHRES(val)     (((val) & 0x1f) << 16)
+ #define TEGRA186_ADMA_CH_FIFO_CTRL_TXSIZE(val)                (((val) & 0x1f) << 8)
+ #define TEGRA186_ADMA_CH_FIFO_CTRL_RXSIZE(val)                ((val) & 0x1f)
  
  #define ADMA_CH_LOWER_SRC_ADDR                                0x34
  #define ADMA_CH_LOWER_TRG_ADDR                                0x3c
  
  #define TEGRA_ADMA_BURST_COMPLETE_TIME                        20
  
- #define ADMA_CH_FIFO_CTRL_DEFAULT     (ADMA_CH_FIFO_CTRL_OVRFW_THRES(1) | \
-                                        ADMA_CH_FIFO_CTRL_STARV_THRES(1))
+ #define TEGRA210_FIFO_CTRL_DEFAULT (TEGRA210_ADMA_CH_FIFO_CTRL_OFLWTHRES(1) | \
+                                   TEGRA210_ADMA_CH_FIFO_CTRL_STRVTHRES(1) | \
+                                   TEGRA210_ADMA_CH_FIFO_CTRL_TXSIZE(3)    | \
+                                   TEGRA210_ADMA_CH_FIFO_CTRL_RXSIZE(3))
+ #define TEGRA186_FIFO_CTRL_DEFAULT (TEGRA186_ADMA_CH_FIFO_CTRL_OFLWTHRES(1) | \
+                                   TEGRA186_ADMA_CH_FIFO_CTRL_STRVTHRES(1) | \
+                                   TEGRA186_ADMA_CH_FIFO_CTRL_TXSIZE(3)    | \
+                                   TEGRA186_ADMA_CH_FIFO_CTRL_RXSIZE(3))
  
  #define ADMA_CH_REG_FIELD_VAL(val, mask, shift)       (((val) & mask) << shift)
  
@@@ -73,7 -95,8 +84,8 @@@ struct tegra_adma
   * @global_int_clear: Register offset of DMA global interrupt clear.
   * @ch_req_tx_shift: Register offset for AHUB transmit channel select.
   * @ch_req_rx_shift: Register offset for AHUB receive channel select.
-  * @ch_base_offset: Reister offset of DMA channel registers.
+  * @ch_base_offset: Register offset of DMA channel registers.
+  * @ch_fifo_ctrl: Default value for channel FIFO CTRL register.
   * @ch_req_mask: Mask for Tx or Rx channel select.
   * @ch_req_max: Maximum number of Tx or Rx channels available.
   * @ch_reg_size: Size of DMA channel register space.
@@@ -86,6 -109,7 +98,7 @@@ struct tegra_adma_chip_data 
        unsigned int ch_req_tx_shift;
        unsigned int ch_req_rx_shift;
        unsigned int ch_base_offset;
+       unsigned int ch_fifo_ctrl;
        unsigned int ch_req_mask;
        unsigned int ch_req_max;
        unsigned int ch_reg_size;
@@@ -589,7 -613,7 +602,7 @@@ static int tegra_adma_set_xfer_params(s
                         ADMA_CH_CTRL_FLOWCTRL_EN;
        ch_regs->config |= cdata->adma_get_burst_config(burst_size);
        ch_regs->config |= ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1);
-       ch_regs->fifo_ctrl = ADMA_CH_FIFO_CTRL_DEFAULT;
+       ch_regs->fifo_ctrl = cdata->ch_fifo_ctrl;
        ch_regs->tc = desc->period_len & ADMA_CH_TC_COUNT_MASK;
  
        return tegra_adma_request_alloc(tdc, direction);
@@@ -773,6 -797,7 +786,7 @@@ static const struct tegra_adma_chip_dat
        .ch_req_tx_shift        = 28,
        .ch_req_rx_shift        = 24,
        .ch_base_offset         = 0,
+       .ch_fifo_ctrl           = TEGRA210_FIFO_CTRL_DEFAULT,
        .ch_req_mask            = 0xf,
        .ch_req_max             = 10,
        .ch_reg_size            = 0x80,
@@@ -786,6 -811,7 +800,7 @@@ static const struct tegra_adma_chip_dat
        .ch_req_tx_shift        = 27,
        .ch_req_rx_shift        = 22,
        .ch_base_offset         = 0x10000,
+       .ch_fifo_ctrl           = TEGRA186_FIFO_CTRL_DEFAULT,
        .ch_req_mask            = 0x1f,
        .ch_req_max             = 20,
        .ch_reg_size            = 0x100,
@@@ -834,16 -860,6 +849,6 @@@ static int tegra_adma_probe(struct plat
                return PTR_ERR(tdma->ahub_clk);
        }
  
-       pm_runtime_enable(&pdev->dev);
-       ret = pm_runtime_get_sync(&pdev->dev);
-       if (ret < 0)
-               goto rpm_disable;
-       ret = tegra_adma_init(tdma);
-       if (ret)
-               goto rpm_put;
        INIT_LIST_HEAD(&tdma->dma_dev.channels);
        for (i = 0; i < tdma->nr_channels; i++) {
                struct tegra_adma_chan *tdc = &tdma->channels[i];
                tdc->tdma = tdma;
        }
  
+       pm_runtime_enable(&pdev->dev);
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (ret < 0)
+               goto rpm_disable;
+       ret = tegra_adma_init(tdma);
+       if (ret)
+               goto rpm_put;
        dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask);
        dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask);
        dma_cap_set(DMA_CYCLIC, tdma->dma_dev.cap_mask);
  
  dma_remove:
        dma_async_device_unregister(&tdma->dma_dev);
- irq_dispose:
-       while (--i >= 0)
-               irq_dispose_mapping(tdma->channels[i].irq);
  rpm_put:
        pm_runtime_put_sync(&pdev->dev);
  rpm_disable:
        pm_runtime_disable(&pdev->dev);
+ irq_dispose:
+       while (--i >= 0)
+               irq_dispose_mapping(tdma->channels[i].irq);
  
        return ret;
  }