[PATCH v2 3/6] dmaengine: dw: Set DMA device max segment size parameter

From: Serge Semin
Date: Fri May 08 2020 - 06:53:35 EST


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.Semin@xxxxxxxxxxxxxxxxxxxx>
Cc: Alexey Malahov <Alexey.Malahov@xxxxxxxxxxxxxxxxxxxx>
Cc: Thomas Bogendoerfer <tsbogend@xxxxxxxxxxxxxxxx>
Cc: Paul Burton <paulburton@xxxxxxxxxx>
Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx>
Cc: Arnd Bergmann <arnd@xxxxxxxx>
Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
Cc: Dan Williams <dan.j.williams@xxxxxxxxx>
Cc: Rob Herring <robh+dt@xxxxxxxxxx>
Cc: linux-mips@xxxxxxxxxxxxxxx
Cc: devicetree@xxxxxxxxxxxxxxx

---

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