dmaengine: zynqmp_dma: fix burst length configuration
authorMatthias Fend <matthias.fend@wolfvision.net>
Wed, 15 Jan 2020 10:22:49 +0000 (11:22 +0100)
committerVinod Koul <vkoul@kernel.org>
Tue, 21 Jan 2020 09:19:30 +0000 (14:49 +0530)
Since the dma engine expects the burst length register content as
power of 2 value, the burst length needs to be converted first.
Additionally add a burst length range check to avoid corrupting unrelated
register bits.

Signed-off-by: Matthias Fend <matthias.fend@wolfvision.net>
Link: https://lore.kernel.org/r/20200115102249.24398-1-matthias.fend@wolfvision.net
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/xilinx/zynqmp_dma.c

index 9c845c0..d47749a 100644 (file)
 /* Max transfer size per descriptor */
 #define ZYNQMP_DMA_MAX_TRANS_LEN       0x40000000
 
+/* Max burst lengths */
+#define ZYNQMP_DMA_MAX_DST_BURST_LEN    32768U
+#define ZYNQMP_DMA_MAX_SRC_BURST_LEN    32768U
+
 /* Reset values for data attributes */
 #define ZYNQMP_DMA_AXCACHE_VAL         0xF
-#define ZYNQMP_DMA_ARLEN_RST_VAL       0xF
-#define ZYNQMP_DMA_AWLEN_RST_VAL       0xF
 
 #define ZYNQMP_DMA_SRC_ISSUE_RST_VAL   0x1F
 
@@ -534,17 +536,19 @@ static void zynqmp_dma_handle_ovfl_int(struct zynqmp_dma_chan *chan, u32 status)
 
 static void zynqmp_dma_config(struct zynqmp_dma_chan *chan)
 {
-       u32 val;
+       u32 val, burst_val;
 
        val = readl(chan->regs + ZYNQMP_DMA_CTRL0);
        val |= ZYNQMP_DMA_POINT_TYPE_SG;
        writel(val, chan->regs + ZYNQMP_DMA_CTRL0);
 
        val = readl(chan->regs + ZYNQMP_DMA_DATA_ATTR);
+       burst_val = __ilog2_u32(chan->src_burst_len);
        val = (val & ~ZYNQMP_DMA_ARLEN) |
-               (chan->src_burst_len << ZYNQMP_DMA_ARLEN_OFST);
+               ((burst_val << ZYNQMP_DMA_ARLEN_OFST) & ZYNQMP_DMA_ARLEN);
+       burst_val = __ilog2_u32(chan->dst_burst_len);
        val = (val & ~ZYNQMP_DMA_AWLEN) |
-               (chan->dst_burst_len << ZYNQMP_DMA_AWLEN_OFST);
+               ((burst_val << ZYNQMP_DMA_AWLEN_OFST) & ZYNQMP_DMA_AWLEN);
        writel(val, chan->regs + ZYNQMP_DMA_DATA_ATTR);
 }
 
@@ -560,8 +564,10 @@ static int zynqmp_dma_device_config(struct dma_chan *dchan,
 {
        struct zynqmp_dma_chan *chan = to_chan(dchan);
 
-       chan->src_burst_len = config->src_maxburst;
-       chan->dst_burst_len = config->dst_maxburst;
+       chan->src_burst_len = clamp(config->src_maxburst, 1U,
+               ZYNQMP_DMA_MAX_SRC_BURST_LEN);
+       chan->dst_burst_len = clamp(config->dst_maxburst, 1U,
+               ZYNQMP_DMA_MAX_DST_BURST_LEN);
 
        return 0;
 }
@@ -887,8 +893,8 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
                return PTR_ERR(chan->regs);
 
        chan->bus_width = ZYNQMP_DMA_BUS_WIDTH_64;
-       chan->dst_burst_len = ZYNQMP_DMA_AWLEN_RST_VAL;
-       chan->src_burst_len = ZYNQMP_DMA_ARLEN_RST_VAL;
+       chan->dst_burst_len = ZYNQMP_DMA_MAX_DST_BURST_LEN;
+       chan->src_burst_len = ZYNQMP_DMA_MAX_SRC_BURST_LEN;
        err = of_property_read_u32(node, "xlnx,bus-width", &chan->bus_width);
        if (err < 0) {
                dev_err(&pdev->dev, "missing xlnx,bus-width property\n");