Maximum block size DW DMAC configuration corresponds to the max segment
size DMA parameter in the DMA core subsystem notation. Lets set it with a
value specific to the probed DW DMA controller. It shall help the DMA
clients to create size-optimized SG-list items for the controller. This in
turn will cause less dw_desc allocations, less LLP reinitializations,
better DMA device performance.

Signed-off-by: Serge Semin <sergey.se...@baikalelectronics.ru>
Cc: Alexey Malahov <alexey.mala...@baikalelectronics.ru>
Cc: Thomas Bogendoerfer <tsbog...@alpha.franken.de>
Cc: Paul Burton <paulbur...@kernel.org>
Cc: Ralf Baechle <r...@linux-mips.org>
Cc: Arnd Bergmann <a...@arndb.de>
Cc: Andy Shevchenko <andriy.shevche...@linux.intel.com>
Cc: Dan Williams <dan.j.willi...@intel.com>
Cc: Rob Herring <robh...@kernel.org>
Cc: linux-m...@vger.kernel.org
Cc: devicet...@vger.kernel.org

---

Changelog v2:
- This is a new patch created in place of the dropped one:
  "dmaengine: dw: Add LLP and block size config accessors".
---
 drivers/dma/dw/core.c | 17 +++++++++++++++++
 drivers/dma/dw/regs.h | 18 ++++++++++--------
 2 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 21cb2a58dbd2..8bcd82c64478 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -1054,6 +1054,7 @@ int do_dma_probe(struct dw_dma_chip *chip)
        struct dw_dma *dw = chip->dw;
        struct dw_dma_platform_data *pdata;
        bool                    autocfg = false;
+       unsigned int            block_size = 0;
        unsigned int            dw_params;
        unsigned int            i;
        int                     err;
@@ -1184,6 +1185,18 @@ int do_dma_probe(struct dw_dma_chip *chip)
                        dwc->block_size = pdata->block_size;
                        dwc->nollp = !pdata->multi_block[i];
                }
+
+               /*
+                * Find maximum block size to be set as the DMA device maximum
+                * segment size. By doing so we'll have size optimized SG-list
+                * items for the channels with biggest block size. This won't
+                * be a problem for the rest of the channels, since they will
+                * still be able to split the requests up by allocating
+                * multiple DW DMA LLP descriptors, which they would have done
+                * anyway.
+                */
+               if (dwc->block_size > block_size)
+                       block_size = dwc->block_size;
        }
 
        /* Clear all interrupts on all channels. */
@@ -1220,6 +1233,10 @@ int do_dma_probe(struct dw_dma_chip *chip)
                             BIT(DMA_MEM_TO_MEM);
        dw->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
 
+       /* Block size corresponds to the maximum sg size */
+       dw->dma.dev->dma_parms = &dw->dma_parms;
+       dma_set_max_seg_size(dw->dma.dev, block_size);
+
        err = dma_async_device_register(&dw->dma);
        if (err)
                goto err_dma_register;
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 3fce66ecee7a..20037d64f961 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -8,6 +8,7 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/dmaengine.h>
 
@@ -308,16 +309,17 @@ static inline struct dw_dma_chan *to_dw_dma_chan(struct 
dma_chan *chan)
 }
 
 struct dw_dma {
-       struct dma_device       dma;
-       char                    name[20];
-       void __iomem            *regs;
-       struct dma_pool         *desc_pool;
-       struct tasklet_struct   tasklet;
+       struct dma_device               dma;
+       struct device_dma_parameters    dma_parms;
+       char                            name[20];
+       void __iomem                    *regs;
+       struct dma_pool                 *desc_pool;
+       struct tasklet_struct           tasklet;
 
        /* channels */
-       struct dw_dma_chan      *chan;
-       u8                      all_chan_mask;
-       u8                      in_use;
+       struct dw_dma_chan              *chan;
+       u8                              all_chan_mask;
+       u8                              in_use;
 
        /* Channel operations */
        void    (*initialize_chan)(struct dw_dma_chan *dwc);
-- 
2.25.1

Reply via email to