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