]> rtime.felk.cvut.cz Git - vajnamar/linux-xlnx.git/commitdiff
dma: xilinx: Fix issues with vdma mulit fstore configuration
authorKedareswara rao Appana <appana.durga.rao@xilinx.com>
Fri, 8 Sep 2017 14:30:47 +0000 (20:00 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Tue, 12 Sep 2017 07:45:47 +0000 (09:45 +0200)
This commit
ie: 'commit 4f143cb03aba ("dmaeninge: xilinx_dma: Fix bug in multiple
frame stores scenario in vdma")'
fixes issues with multiple fstore by using circular mode feature.
This implementation has a limitation as user needs to enable a hidden
configuration option(c_debug_all) in the IP while creating the design.

If user not aware of this h/w option and submits more frames
then driver throughs a warning asking to enable the
hidden configuration option.

This patches fixes these issues by using the park mode feature.
With this patch driver continuously parks through frame buffers
based on the number of frames user submitted.

Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
drivers/dma/xilinx/xilinx_dma.c

index eec1c8148736a8136b95b265dceda1014bf58305..e7a5a6a090045584f184cf28ded726240eba0be9 100644 (file)
@@ -66,8 +66,6 @@ Optional child node properties:
 Optional child node properties for VDMA:
 - xlnx,genlock-mode: Tells Genlock synchronization is
        enabled/disabled in hardware.
-- xlnx,fstore-enable: boolean; if defined, it indicates that controller
-       supports frame store configuration.
 Optional child node properties for AXI DMA:
 -dma-channels: Number of dma channels in child node.
 
index b92d40dfbe2d6bb011f798c064ca2395da1abc57..d1542f2bf7a3f3a987a35440512094e65f26f473 100644 (file)
@@ -99,7 +99,9 @@
 #define XILINX_DMA_REG_FRMPTR_STS              0x0024
 #define XILINX_DMA_REG_PARK_PTR                0x0028
 #define XILINX_DMA_PARK_PTR_WR_REF_SHIFT       8
+#define XILINX_DMA_PARK_PTR_WR_REF_MASK                GENMASK(12, 8)
 #define XILINX_DMA_PARK_PTR_RD_REF_SHIFT       0
+#define XILINX_DMA_PARK_PTR_RD_REF_MASK                GENMASK(4, 0)
 #define XILINX_DMA_REG_VDMA_VERSION            0x002c
 
 /* Register Direct Mode Registers */
@@ -324,7 +326,6 @@ struct xilinx_dma_tx_descriptor {
  * @genlock: Support genlock mode
  * @err: Channel has errors
  * @idle: Check for channel idle
- * @has_fstoreen: Check for frame store configuration
  * @tasklet: Cleanup work after irq
  * @config: Device configuration info
  * @flush_on_fsync: Flush on Frame sync
@@ -360,7 +361,6 @@ struct xilinx_dma_chan {
        bool genlock;
        bool err;
        bool idle;
-       bool has_fstoreen;
        struct tasklet_struct tasklet;
        struct xilinx_vdma_config config;
        bool flush_on_fsync;
@@ -1032,7 +1032,7 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
 {
        struct xilinx_vdma_config *config = &chan->config;
        struct xilinx_dma_tx_descriptor *desc, *tail_desc;
-       u32 reg;
+       u32 reg, j;
        struct xilinx_vdma_tx_segment *tail_segment;
 
        /* This function was invoked with lock held */
@@ -1045,27 +1045,6 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
        if (list_empty(&chan->pending_list))
                return;
 
-       /*
-        * Note: When VDMA is built with default h/w configuration
-        * User should submit frames upto H/W configured.
-        * If users submits less than h/w configured
-        * VDMA engine tries to write to a invalid location
-        * Results undefined behaviour/memory corruption.
-        *
-        * If user would like to submit frames less than h/w capable
-        * On S2MM side please enable debug info 13 at the h/w level
-        * On MM2S side please enable debug info 6 at the h/w level
-        * It will allows the frame buffers numbers to be modified at runtime.
-        */
-       if (!chan->has_fstoreen &&
-            chan->desc_pendingcount < chan->num_frms) {
-               dev_warn(chan->dev, "Frame Store Configuration is not enabled at the\n");
-               dev_warn(chan->dev, "H/w level enable Debug info 13 or 6 at the h/w level\n");
-               dev_warn(chan->dev, "OR Submit the frames upto h/w Capable\n\r");
-
-               return;
-       }
-
        desc = list_first_entry(&chan->pending_list,
                                struct xilinx_dma_tx_descriptor, node);
        tail_desc = list_last_entry(&chan->pending_list,
@@ -1090,10 +1069,6 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
        else
                reg &= ~XILINX_DMA_DMACR_FRAMECNT_EN;
 
-       /* Configure channel to allow number frame buffers */
-       dma_ctrl_write(chan, XILINX_DMA_REG_FRMSTORE,
-                       chan->desc_pendingcount);
-
        /*
         * With SG, start with circular mode, so that BDs can be fetched.
         * In direct register mode, if not parking, enable circular mode
@@ -1106,17 +1081,16 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
 
        dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
 
-       if (config->park && (config->park_frm >= 0) &&
-                       (config->park_frm < chan->num_frms)) {
-               if (chan->direction == DMA_MEM_TO_DEV)
-                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
-                               config->park_frm <<
-                                       XILINX_DMA_PARK_PTR_RD_REF_SHIFT);
-               else
-                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
-                               config->park_frm <<
-                                       XILINX_DMA_PARK_PTR_WR_REF_SHIFT);
+       j = chan->desc_submitcount;
+       reg = dma_read(chan, XILINX_DMA_REG_PARK_PTR);
+       if (chan->direction == DMA_MEM_TO_DEV) {
+               reg &= ~XILINX_DMA_PARK_PTR_RD_REF_MASK;
+               reg |= j << XILINX_DMA_PARK_PTR_RD_REF_SHIFT;
+       } else {
+               reg &= ~XILINX_DMA_PARK_PTR_WR_REF_MASK;
+               reg |= j << XILINX_DMA_PARK_PTR_WR_REF_SHIFT;
        }
+       dma_write(chan, XILINX_DMA_REG_PARK_PTR, reg);
 
        /* Start the hardware */
        xilinx_dma_start(chan);
@@ -1132,34 +1106,23 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
                chan->desc_pendingcount = 0;
        } else {
                struct xilinx_vdma_tx_segment *segment, *last = NULL;
-               int i = 0, j = 0;
+               int i = 0;
 
                if (chan->desc_submitcount < chan->num_frms)
                        i = chan->desc_submitcount;
 
-               for (j = 0; j < chan->num_frms; ) {
-                       list_for_each_entry(segment, &desc->segments, node) {
-                               if (chan->ext_addr)
-                                       vdma_desc_write_64(chan,
-                                         XILINX_VDMA_REG_START_ADDRESS_64(i++),
-                                         segment->hw.buf_addr,
-                                         segment->hw.buf_addr_msb);
-                               else
-                                       vdma_desc_write(chan,
-                                           XILINX_VDMA_REG_START_ADDRESS(i++),
-                                           segment->hw.buf_addr);
-
-                               last = segment;
-                       }
-                       list_del(&desc->node);
-                       list_add_tail(&desc->node, &chan->active_list);
-                       j++;
-                       if (list_empty(&chan->pending_list) ||
-                           (i == chan->num_frms))
-                               break;
-                       desc = list_first_entry(&chan->pending_list,
-                                               struct xilinx_dma_tx_descriptor,
-                                               node);
+               list_for_each_entry(segment, &desc->segments, node) {
+                       if (chan->ext_addr)
+                               vdma_desc_write_64(chan,
+                                 XILINX_VDMA_REG_START_ADDRESS_64(i++),
+                                 segment->hw.buf_addr,
+                                 segment->hw.buf_addr_msb);
+                       else
+                               vdma_desc_write(chan,
+                                   XILINX_VDMA_REG_START_ADDRESS(i++),
+                                   segment->hw.buf_addr);
+
+                       last = segment;
                }
 
                if (!last)
@@ -1171,8 +1134,10 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
                                last->hw.stride);
                vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize);
 
-               chan->desc_submitcount += j;
-               chan->desc_pendingcount -= j;
+               chan->desc_submitcount++;
+               chan->desc_pendingcount--;
+               list_del(&desc->node);
+               list_add_tail(&desc->node, &chan->active_list);
                if (chan->desc_submitcount == chan->num_frms)
                        chan->desc_submitcount = 0;
        }
@@ -2391,7 +2356,6 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
        has_dre = of_property_read_bool(node, "xlnx,include-dre");
 
        chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode");
-       chan->has_fstoreen = of_property_read_bool(node, "xlnx,fstore-enable");
 
        err = of_property_read_u32(node, "xlnx,datawidth", &value);
        if (err) {
@@ -2417,6 +2381,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
 
                chan->ctrl_offset = XILINX_DMA_MM2S_CTRL_OFFSET;
                if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+                       chan->config.park = 1;
                        chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET;
 
                        if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||
@@ -2434,6 +2399,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
 
                chan->ctrl_offset = XILINX_DMA_S2MM_CTRL_OFFSET;
                if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+                       chan->config.park = 1;
                        chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
 
                        if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||