Merge remote-tracking branch 'slave-dma/next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Fri, 8 Feb 2019 04:44:40 +0000 (15:44 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Fri, 8 Feb 2019 04:44:40 +0000 (15:44 +1100)
1  2 
drivers/dma/imx-dma.c
drivers/dma/imx-sdma.c
drivers/dma/xilinx/xilinx_dma.c

diff --combined drivers/dma/imx-dma.c
@@@ -278,14 -278,14 +278,14 @@@ static int imxdma_hw_chain(struct imxdm
  /*
   * imxdma_sg_next - prepare next chunk for scatter-gather DMA emulation
   */
- static inline int imxdma_sg_next(struct imxdma_desc *d)
+ static inline void imxdma_sg_next(struct imxdma_desc *d)
  {
        struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
        struct imxdma_engine *imxdma = imxdmac->imxdma;
        struct scatterlist *sg = d->sg;
-       unsigned long now;
+       size_t now;
  
-       now = min(d->len, sg_dma_len(sg));
+       now = min_t(size_t, d->len, sg_dma_len(sg));
        if (d->len != IMX_DMA_LENGTH_LOOP)
                d->len -= now;
  
                 imx_dmav1_readl(imxdma, DMA_DAR(imxdmac->channel)),
                 imx_dmav1_readl(imxdma, DMA_SAR(imxdmac->channel)),
                 imx_dmav1_readl(imxdma, DMA_CNTR(imxdmac->channel)));
-       return now;
  }
  
  static void imxdma_enable_hw(struct imxdma_desc *d)
@@@ -618,7 -616,7 +616,7 @@@ static void imxdma_tasklet(unsigned lon
  {
        struct imxdma_channel *imxdmac = (void *)data;
        struct imxdma_engine *imxdma = imxdmac->imxdma;
 -      struct imxdma_desc *desc;
 +      struct imxdma_desc *desc, *next_desc;
        unsigned long flags;
  
        spin_lock_irqsave(&imxdma->lock, flags);
        list_move_tail(imxdmac->ld_active.next, &imxdmac->ld_free);
  
        if (!list_empty(&imxdmac->ld_queue)) {
 -              desc = list_first_entry(&imxdmac->ld_queue, struct imxdma_desc,
 -                                      node);
 +              next_desc = list_first_entry(&imxdmac->ld_queue,
 +                                           struct imxdma_desc, node);
                list_move_tail(imxdmac->ld_queue.next, &imxdmac->ld_active);
 -              if (imxdma_xfer_desc(desc) < 0)
 +              if (imxdma_xfer_desc(next_desc) < 0)
                        dev_warn(imxdma->dev, "%s: channel: %d couldn't xfer desc\n",
                                 __func__, imxdmac->channel);
        }
diff --combined drivers/dma/imx-sdma.c
@@@ -377,6 -377,7 +377,7 @@@ struct sdma_channel 
        unsigned long                   watermark_level;
        u32                             shp_addr, per_addr;
        enum dma_status                 status;
+       bool                            context_loaded;
        struct imx_dma_data             data;
        struct work_struct              terminate_worker;
  };
@@@ -677,7 -678,7 +678,7 @@@ static int sdma_load_script(struct sdma
        int ret;
        unsigned long flags;
  
-       buf_virt = dma_alloc_coherent(NULL, size, &buf_phys, GFP_KERNEL);
+       buf_virt = dma_alloc_coherent(sdma->dev, size, &buf_phys, GFP_KERNEL);
        if (!buf_virt) {
                return -ENOMEM;
        }
  
        spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
  
-       dma_free_coherent(NULL, size, buf_virt, buf_phys);
+       dma_free_coherent(sdma->dev, size, buf_virt, buf_phys);
  
        return ret;
  }
@@@ -970,6 -971,9 +971,9 @@@ static int sdma_load_context(struct sdm
        int ret;
        unsigned long flags;
  
+       if (sdmac->context_loaded)
+               return 0;
        if (sdmac->direction == DMA_DEV_TO_MEM)
                load_address = sdmac->pc_from_device;
        else if (sdmac->direction == DMA_DEV_TO_DEV)
  
        spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
  
+       sdmac->context_loaded = true;
        return ret;
  }
  
@@@ -1051,6 -1057,7 +1057,7 @@@ static void sdma_channel_terminate_work
        sdmac->desc = NULL;
        spin_unlock_irqrestore(&sdmac->vc.lock, flags);
        vchan_dma_desc_free_list(&sdmac->vc, &head);
+       sdmac->context_loaded = false;
  }
  
  static int sdma_disable_channel_async(struct dma_chan *chan)
@@@ -1182,8 -1189,8 +1189,8 @@@ static int sdma_request_channel0(struc
  {
        int ret = -EBUSY;
  
-       sdma->bd0 = dma_alloc_coherent(NULL, PAGE_SIZE, &sdma->bd0_phys,
 -      sdma->bd0 = dma_zalloc_coherent(sdma->dev, PAGE_SIZE, &sdma->bd0_phys,
 -                                      GFP_NOWAIT);
++      sdma->bd0 = dma_alloc_coherent(sdma->dev, PAGE_SIZE, &sdma->bd0_phys,
 +                                     GFP_NOWAIT);
        if (!sdma->bd0) {
                ret = -ENOMEM;
                goto out;
@@@ -1205,8 -1212,8 +1212,8 @@@ static int sdma_alloc_bd(struct sdma_de
        u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
        int ret = 0;
  
-       desc->bd = dma_alloc_coherent(NULL, bd_size, &desc->bd_phys,
-                                     GFP_NOWAIT);
 -      desc->bd = dma_zalloc_coherent(desc->sdmac->sdma->dev, bd_size,
 -                                     &desc->bd_phys, GFP_NOWAIT);
++      desc->bd = dma_alloc_coherent(desc->sdmac->sdma->dev, bd_size,
++                                    &desc->bd_phys, GFP_NOWAIT);
        if (!desc->bd) {
                ret = -ENOMEM;
                goto out;
@@@ -1219,7 -1226,8 +1226,8 @@@ static void sdma_free_bd(struct sdma_de
  {
        u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
  
-       dma_free_coherent(NULL, bd_size, desc->bd, desc->bd_phys);
+       dma_free_coherent(desc->sdmac->sdma->dev, bd_size, desc->bd,
+                         desc->bd_phys);
  }
  
  static void sdma_desc_free(struct virt_dma_desc *vd)
@@@ -1842,7 -1850,7 +1850,7 @@@ static int sdma_init(struct sdma_engin
        /* Be sure SDMA has not started yet */
        writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
  
-       sdma->channel_control = dma_alloc_coherent(NULL,
+       sdma->channel_control = dma_alloc_coherent(sdma->dev,
                        MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
                        sizeof(struct sdma_context_data),
                        &ccb_phys, GFP_KERNEL);
@@@ -86,6 -86,7 +86,7 @@@
  #define XILINX_DMA_DMASR_DMA_DEC_ERR          BIT(6)
  #define XILINX_DMA_DMASR_DMA_SLAVE_ERR                BIT(5)
  #define XILINX_DMA_DMASR_DMA_INT_ERR          BIT(4)
+ #define XILINX_DMA_DMASR_SG_MASK              BIT(3)
  #define XILINX_DMA_DMASR_IDLE                 BIT(1)
  #define XILINX_DMA_DMASR_HALTED               BIT(0)
  #define XILINX_DMA_DMASR_DELAY_MASK           GENMASK(31, 24)
  #define XILINX_DMA_REG_BTT            0x28
  
  /* AXI DMA Specific Masks/Bit fields */
- #define XILINX_DMA_MAX_TRANS_LEN      GENMASK(22, 0)
+ #define XILINX_DMA_MAX_TRANS_LEN_MIN  8
+ #define XILINX_DMA_MAX_TRANS_LEN_MAX  23
+ #define XILINX_DMA_V2_MAX_TRANS_LEN_MAX       26
  #define XILINX_DMA_CR_COALESCE_MAX    GENMASK(23, 16)
  #define XILINX_DMA_CR_CYCLIC_BD_EN_MASK       BIT(4)
  #define XILINX_DMA_CR_COALESCE_SHIFT  16
@@@ -412,7 -415,6 +415,6 @@@ struct xilinx_dma_config 
   * @dev: Device Structure
   * @common: DMA device structure
   * @chan: Driver specific DMA channel
-  * @has_sg: Specifies whether Scatter-Gather is present or not
   * @mcdma: Specifies whether Multi-Channel is present or not
   * @flush_on_fsync: Flush on frame sync
   * @ext_addr: Indicates 64 bit addressing is supported by dma device
   * @rxs_clk: DMA s2mm stream clock
   * @nr_channels: Number of channels DMA device supports
   * @chan_id: DMA channel identifier
+  * @max_buffer_len: Max buffer length
   */
  struct xilinx_dma_device {
        void __iomem *regs;
        struct device *dev;
        struct dma_device common;
        struct xilinx_dma_chan *chan[XILINX_DMA_MAX_CHANS_PER_DEVICE];
-       bool has_sg;
        bool mcdma;
        u32 flush_on_fsync;
        bool ext_addr;
        struct clk *rxs_clk;
        u32 nr_channels;
        u32 chan_id;
+       u32 max_buffer_len;
  };
  
  /* Macros */
@@@ -879,9 -882,10 +882,9 @@@ static int xilinx_dma_alloc_chan_resour
         */
        if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
                /* Allocate the buffer descriptors. */
 -              chan->seg_v = dma_zalloc_coherent(chan->dev,
 -                                                sizeof(*chan->seg_v) *
 -                                                XILINX_DMA_NUM_DESCS,
 -                                                &chan->seg_p, GFP_KERNEL);
 +              chan->seg_v = dma_alloc_coherent(chan->dev,
 +                                               sizeof(*chan->seg_v) * XILINX_DMA_NUM_DESCS,
 +                                               &chan->seg_p, GFP_KERNEL);
                if (!chan->seg_v) {
                        dev_err(chan->dev,
                                "unable to allocate channel %d descriptors\n",
                 * so allocating a desc segment during channel allocation for
                 * programming tail descriptor.
                 */
 -              chan->cyclic_seg_v = dma_zalloc_coherent(chan->dev,
 -                                      sizeof(*chan->cyclic_seg_v),
 -                                      &chan->cyclic_seg_p, GFP_KERNEL);
 +              chan->cyclic_seg_v = dma_alloc_coherent(chan->dev,
 +                                                      sizeof(*chan->cyclic_seg_v),
 +                                                      &chan->cyclic_seg_p,
 +                                                      GFP_KERNEL);
                if (!chan->cyclic_seg_v) {
                        dev_err(chan->dev,
                                "unable to allocate desc segment for cyclic DMA\n");
        return 0;
  }
  
+ /**
+  * xilinx_dma_calc_copysize - Calculate the amount of data to copy
+  * @chan: Driver specific DMA channel
+  * @size: Total data that needs to be copied
+  * @done: Amount of data that has been already copied
+  *
+  * Return: Amount of data that has to be copied
+  */
+ static int xilinx_dma_calc_copysize(struct xilinx_dma_chan *chan,
+                                   int size, int done)
+ {
+       size_t copy;
+       copy = min_t(size_t, size - done,
+                    chan->xdev->max_buffer_len);
+       if ((copy + done < size) &&
+           chan->xdev->common.copy_align) {
+               /*
+                * If this is not the last descriptor, make sure
+                * the next one will be properly aligned
+                */
+               copy = rounddown(copy,
+                                (1 << chan->xdev->common.copy_align));
+       }
+       return copy;
+ }
  /**
   * xilinx_dma_tx_status - Get DMA transaction status
   * @dchan: DMA channel
@@@ -992,7 -1023,7 +1023,7 @@@ static enum dma_status xilinx_dma_tx_st
                        list_for_each_entry(segment, &desc->segments, node) {
                                hw = &segment->hw;
                                residue += (hw->control - hw->status) &
-                                          XILINX_DMA_MAX_TRANS_LEN;
+                                          chan->xdev->max_buffer_len;
                        }
                }
                spin_unlock_irqrestore(&chan->lock, flags);
@@@ -1070,7 -1101,8 +1101,8 @@@ static void xilinx_vdma_start_transfer(
        struct xilinx_vdma_config *config = &chan->config;
        struct xilinx_dma_tx_descriptor *desc, *tail_desc;
        u32 reg, j;
-       struct xilinx_vdma_tx_segment *tail_segment;
+       struct xilinx_vdma_tx_segment *segment, *last = NULL;
+       int i = 0;
  
        /* This function was invoked with lock held */
        if (chan->err)
        tail_desc = list_last_entry(&chan->pending_list,
                                    struct xilinx_dma_tx_descriptor, node);
  
-       tail_segment = list_last_entry(&tail_desc->segments,
-                                      struct xilinx_vdma_tx_segment, node);
-       /*
-        * If hardware is idle, then all descriptors on the running lists are
-        * done, start new transfers
-        */
-       if (chan->has_sg)
-               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
-                               desc->async_tx.phys);
        /* Configure the hardware using info in the config structure */
        if (chan->has_vflip) {
                reg = dma_read(chan, XILINX_VDMA_REG_ENABLE_VERTICAL_FLIP);
        else
                reg &= ~XILINX_DMA_DMACR_FRAMECNT_EN;
  
-       /*
-        * With SG, start with circular mode, so that BDs can be fetched.
-        * In direct register mode, if not parking, enable circular mode
-        */
-       if (chan->has_sg || !config->park)
-               reg |= XILINX_DMA_DMACR_CIRC_EN;
+       /* If not parking, enable circular mode */
        if (config->park)
                reg &= ~XILINX_DMA_DMACR_CIRC_EN;
+       else
+               reg |= XILINX_DMA_DMACR_CIRC_EN;
  
        dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
  
                return;
  
        /* Start the transfer */
-       if (chan->has_sg) {
-               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
-                               tail_segment->phys);
-               list_splice_tail_init(&chan->pending_list, &chan->active_list);
-               chan->desc_pendingcount = 0;
-       } else {
-               struct xilinx_vdma_tx_segment *segment, *last = NULL;
-               int i = 0;
-               if (chan->desc_submitcount < chan->num_frms)
-                       i = chan->desc_submitcount;
-               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,
+       if (chan->desc_submitcount < chan->num_frms)
+               i = chan->desc_submitcount;
+       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;
-               }
+               last = segment;
+       }
  
-               if (!last)
-                       return;
+       if (!last)
+               return;
  
-               /* HW expects these parameters to be same for one transaction */
-               vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize);
-               vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE,
-                               last->hw.stride);
-               vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize);
+       /* HW expects these parameters to be same for one transaction */
+       vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize);
+       vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE,
+                       last->hw.stride);
+       vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize);
  
-               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;
-       }
+       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;
  
        chan->idle = false;
  }
@@@ -1254,7 -1261,7 +1261,7 @@@ static void xilinx_cdma_start_transfer(
  
                /* Start the transfer */
                dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
-                               hw->control & XILINX_DMA_MAX_TRANS_LEN);
+                               hw->control & chan->xdev->max_buffer_len);
        }
  
        list_splice_tail_init(&chan->pending_list, &chan->active_list);
@@@ -1357,7 -1364,7 +1364,7 @@@ static void xilinx_dma_start_transfer(s
  
                /* Start the transfer */
                dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
-                              hw->control & XILINX_DMA_MAX_TRANS_LEN);
+                              hw->control & chan->xdev->max_buffer_len);
        }
  
        list_splice_tail_init(&chan->pending_list, &chan->active_list);
@@@ -1718,7 -1725,7 +1725,7 @@@ xilinx_cdma_prep_memcpy(struct dma_cha
        struct xilinx_cdma_tx_segment *segment;
        struct xilinx_cdma_desc_hw *hw;
  
-       if (!len || len > XILINX_DMA_MAX_TRANS_LEN)
+       if (!len || len > chan->xdev->max_buffer_len)
                return NULL;
  
        desc = xilinx_dma_alloc_tx_descriptor(chan);
@@@ -1808,8 -1815,8 +1815,8 @@@ static struct dma_async_tx_descriptor *
                         * Calculate the maximum number of bytes to transfer,
                         * making sure it is less than the hw limit
                         */
-                       copy = min_t(size_t, sg_dma_len(sg) - sg_used,
-                                    XILINX_DMA_MAX_TRANS_LEN);
+                       copy = xilinx_dma_calc_copysize(chan, sg_dma_len(sg),
+                                                       sg_used);
                        hw = &segment->hw;
  
                        /* Fill in the descriptor */
@@@ -1913,8 -1920,8 +1920,8 @@@ static struct dma_async_tx_descriptor *
                         * Calculate the maximum number of bytes to transfer,
                         * making sure it is less than the hw limit
                         */
-                       copy = min_t(size_t, period_len - sg_used,
-                                    XILINX_DMA_MAX_TRANS_LEN);
+                       copy = xilinx_dma_calc_copysize(chan, period_len,
+                                                       sg_used);
                        hw = &segment->hw;
                        xilinx_axidma_buf(chan, hw, buf_addr, sg_used,
                                          period_len * i);
@@@ -2389,7 -2396,6 +2396,6 @@@ static int xilinx_dma_chan_probe(struc
  
        chan->dev = xdev->dev;
        chan->xdev = xdev;
-       chan->has_sg = xdev->has_sg;
        chan->desc_pendingcount = 0x0;
        chan->ext_addr = xdev->ext_addr;
        /* This variable ensures that descriptors are not
                chan->stop_transfer = xilinx_dma_stop_transfer;
        }
  
+       /* check if SG is enabled (only for AXIDMA and CDMA) */
+       if (xdev->dma_config->dmatype != XDMA_TYPE_VDMA) {
+               if (dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
+                   XILINX_DMA_DMASR_SG_MASK)
+                       chan->has_sg = true;
+               dev_dbg(chan->dev, "ch %d: SG %s\n", chan->id,
+                       chan->has_sg ? "enabled" : "disabled");
+       }
        /* Initialize the tasklet */
        tasklet_init(&chan->tasklet, xilinx_dma_do_tasklet,
                        (unsigned long)chan);
@@@ -2596,7 -2611,7 +2611,7 @@@ static int xilinx_dma_probe(struct plat
        struct xilinx_dma_device *xdev;
        struct device_node *child, *np = pdev->dev.of_node;
        struct resource *io;
-       u32 num_frames, addr_width;
+       u32 num_frames, addr_width, len_width;
        int i, err;
  
        /* Allocate and initialize the DMA engine structure */
                return PTR_ERR(xdev->regs);
  
        /* Retrieve the DMA engine properties from the device tree */
-       xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
-       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
+       xdev->max_buffer_len = GENMASK(XILINX_DMA_MAX_TRANS_LEN_MAX - 1, 0);
+       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
                xdev->mcdma = of_property_read_bool(node, "xlnx,mcdma");
+               if (!of_property_read_u32(node, "xlnx,sg-length-width",
+                                         &len_width)) {
+                       if (len_width < XILINX_DMA_MAX_TRANS_LEN_MIN ||
+                           len_width > XILINX_DMA_V2_MAX_TRANS_LEN_MAX) {
+                               dev_warn(xdev->dev,
+                                        "invalid xlnx,sg-length-width property value. Using default width\n");
+                       } else {
+                               if (len_width > XILINX_DMA_MAX_TRANS_LEN_MAX)
+                                       dev_warn(xdev->dev, "Please ensure that IP supports buffer length > 23 bits\n");
+                               xdev->max_buffer_len =
+                                       GENMASK(len_width - 1, 0);
+                       }
+               }
+       }
  
        if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
                err = of_property_read_u32(node, "xlnx,num-fstores",