summaryrefslogtreecommitdiffstats
path: root/drivers/dma/dw/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-08-07 12:41:36 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-08-07 12:41:36 -0700
commitce615f5c1f73537c8267035d58b3d0c70e19b8da (patch)
tree54b8e1d34536eed62d898e7d9e81779f6728d286 /drivers/dma/dw/core.c
parent81e11336d97e7a4c25a65c302ef2bf9cd9808ed4 (diff)
parent00043a2689232631f39ebbf6719d545b1d799086 (diff)
downloadlinux-ce615f5c1f73537c8267035d58b3d0c70e19b8da.tar.bz2
Merge tag 'dmaengine-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine
Pull dmaengine updates from Vinod Koul: "Core: - Support out of order dma completion - Support for repeating transaction New controllers: - Support for Actions S700 DMA engine - Renesas R8A774E1, r8a7742 controller binding - New driver for Xilinx DPDMA controller Other: - Support of out of order dma completion in idxd driver - W=1 warning cleanup of subsystem - Updates to ti-k3-dma, dw, idxd drivers" * tag 'dmaengine-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine: (68 commits) dmaengine: dw: Don't include unneeded header to platform data header dmaengine: Actions: Add support for S700 DMA engine dmaengine: Actions: get rid of bit fields from dma descriptor dt-bindings: dmaengine: convert Actions Semi Owl SoCs bindings to yaml dmaengine: idxd: add missing invalid flags field to completion dmaengine: dw: Initialize max_sg_burst capability dmaengine: dw: Introduce max burst length hw config dmaengine: dw: Initialize min and max burst DMA device capability dmaengine: dw: Set DMA device max segment size parameter dmaengine: dw: Take HC_LLP flag into account for noLLP auto-config dmaengine: Introduce DMA-device device_caps callback dmaengine: Introduce max SG burst capability dmaengine: Introduce min burst length capability dt-bindings: dma: dw: Add max burst transaction length property dt-bindings: dma: dw: Convert DW DMAC to DT binding dmaengine: ti: k3-udma: Query throughput level information from hardware dmaengine: ti: k3-udma: Use defines for capabilities register parsing dmaengine: xilinx: dpdma: Fix kerneldoc warning dmaengine: xilinx: dpdma: add missing kernel doc dmaengine: xilinx: dpdma: remove comparison of unsigned expression ...
Diffstat (limited to 'drivers/dma/dw/core.c')
-rw-r--r--drivers/dma/dw/core.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index a1b56f52db2f..4700f2e87a62 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -786,6 +786,11 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
+ dwc->dma_sconfig.src_maxburst =
+ clamp(dwc->dma_sconfig.src_maxburst, 0U, dwc->max_burst);
+ dwc->dma_sconfig.dst_maxburst =
+ clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst);
+
dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);
@@ -1037,6 +1042,25 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
}
+static void dwc_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
+{
+ struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+
+ caps->max_burst = dwc->max_burst;
+
+ /*
+ * It might be crucial for some devices to have the hardware
+ * accelerated multi-block transfers supported, aka LLPs in DW DMAC
+ * notation. So if LLPs are supported then max_sg_burst is set to
+ * zero which means unlimited number of SG entries can be handled in a
+ * single DMA transaction, otherwise it's just one SG entry.
+ */
+ if (dwc->nollp)
+ caps->max_sg_burst = 1;
+ else
+ caps->max_sg_burst = 0;
+}
+
int do_dma_probe(struct dw_dma_chip *chip)
{
struct dw_dma *dw = chip->dw;
@@ -1166,11 +1190,23 @@ int do_dma_probe(struct dw_dma_chip *chip)
*/
dwc->block_size =
(4 << ((pdata->block_size >> 4 * i) & 0xf)) - 1;
+
+ /*
+ * According to the DW DMA databook the true scatter-
+ * gether LLPs aren't available if either multi-block
+ * config is disabled (CHx_MULTI_BLK_EN == 0) or the
+ * LLP register is hard-coded to zeros
+ * (CHx_HC_LLP == 1).
+ */
dwc->nollp =
- (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0;
+ (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0 ||
+ (dwc_params >> DWC_PARAMS_HC_LLP & 0x1) == 1;
+ dwc->max_burst =
+ (0x4 << (dwc_params >> DWC_PARAMS_MSIZE & 0x7));
} else {
dwc->block_size = pdata->block_size;
dwc->nollp = !pdata->multi_block[i];
+ dwc->max_burst = pdata->max_burst[i] ?: DW_DMA_MAX_BURST;
}
}
@@ -1193,6 +1229,7 @@ int do_dma_probe(struct dw_dma_chip *chip)
dw->dma.device_prep_dma_memcpy = dwc_prep_dma_memcpy;
dw->dma.device_prep_slave_sg = dwc_prep_slave_sg;
+ dw->dma.device_caps = dwc_caps;
dw->dma.device_config = dwc_config;
dw->dma.device_pause = dwc_pause;
dw->dma.device_resume = dwc_resume;
@@ -1202,12 +1239,21 @@ int do_dma_probe(struct dw_dma_chip *chip)
dw->dma.device_issue_pending = dwc_issue_pending;
/* DMA capabilities */
+ dw->dma.min_burst = DW_DMA_MIN_BURST;
+ dw->dma.max_burst = DW_DMA_MAX_BURST;
dw->dma.src_addr_widths = DW_DMA_BUSWIDTHS;
dw->dma.dst_addr_widths = DW_DMA_BUSWIDTHS;
dw->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
BIT(DMA_MEM_TO_MEM);
dw->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+ /*
+ * For now there is no hardware with non uniform maximum block size
+ * across all of the device channels, so we set the maximum segment
+ * size as the block size found for the very first channel.
+ */
+ dma_set_max_seg_size(dw->dma.dev, dw->chan[0].block_size);
+
err = dma_async_device_register(&dw->dma);
if (err)
goto err_dma_register;