aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-12-09 06:35:53 +0900
committerLinus Torvalds <torvalds@linux-foundation.org>2025-12-09 06:35:53 +0900
commit990fa99821b3349a766881c9f152561f722213e3 (patch)
treef28fc609355cc69fc5b838e82bc39e707515f6de
parent0623fdf30b1105c22f58baeeca954c803bdf5f8b (diff)
parent2b11e7403a8ed816fce38b57cb88e04d997aa7af (diff)
downloadtip-990fa99821b3349a766881c9f152561f722213e3.tar.gz
Merge tag 'dmaengine-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine
Pull dmaengine updates from Vinod Koul: - Renesas driver conversion to RUNTIME_PM_OPS() etc - Dropping module alias on bunch of drivers - GPI Block event interrupt support in Qualcomm driver and updates to I2C driver as well * tag 'dmaengine-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine: (23 commits) dt-bindings: dma: xilinx: Simplify dma-coherent property dmaengine: fsl-edma: configure tcd attr with separate src and dst settings dmaengine: st_fdma: drop unused module alias dmaengine: bcm2835: enable compile testing dmaengine: tegra210-adma: drop unused module alias dmaengine: sprd: drop unused module alias dmaengine: mmp_tdma: drop unnecessary OF node check in remove dmaengine: mmp_tdma: drop unused module alias dmaengine: k3dma: drop unused module alias dmaengine: fsl-qdma: drop unused module alias dmaengine: fsl-edma: drop unused module alias dmaengine: dw: drop unused module alias dmaengine: bcm2835: drop unused module alias dmaengine: at_hdmac: add COMPILE_TEST support dmaengine: at_hdmac: fix formats under 64-bit i2c: i2c-qcom-geni: Add Block event interrupt support dmaengine: qcom: gpi: Add GPI Block event interrupt support dmaengine: idxd: drain ATS translations when disabling WQ dmaengine: sh: Kconfig: Drop ARCH_R7S72100/ARCH_RZG2L dependency dmaengine: rcar-dmac: Convert to NOIRQ_SYSTEM_SLEEP/RUNTIME_PM_OPS() ...
-rw-r--r--Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml3
-rw-r--r--drivers/dma/Kconfig4
-rw-r--r--drivers/dma/at_hdmac.c6
-rw-r--r--drivers/dma/bcm2835-dma.c1
-rw-r--r--drivers/dma/dw/platform.c5
-rw-r--r--drivers/dma/fsl-edma-common.c45
-rw-r--r--drivers/dma/fsl-edma-main.c1
-rw-r--r--drivers/dma/fsl-qdma.c1
-rw-r--r--drivers/dma/idxd/device.c19
-rw-r--r--drivers/dma/k3dma.c1
-rw-r--r--drivers/dma/mmp_tdma.c4
-rw-r--r--drivers/dma/nbpfaxi.c6
-rw-r--r--drivers/dma/qcom/gpi.c11
-rw-r--r--drivers/dma/sh/Kconfig2
-rw-r--r--drivers/dma/sh/rcar-dmac.c16
-rw-r--r--drivers/dma/sh/usb-dmac.c11
-rw-r--r--drivers/dma/sprd-dma.c1
-rw-r--r--drivers/dma/st_fdma.c1
-rw-r--r--drivers/dma/tegra210-adma.c1
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c248
20 files changed, 302 insertions, 85 deletions
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
index b5399c65a7315b..2da86037ad79ee 100644
--- a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
+++ b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
@@ -59,8 +59,7 @@ properties:
power-domains:
maxItems: 1
- dma-coherent:
- description: present if dma operations are coherent
+ dma-coherent: true
required:
- "#dma-cells"
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index b8a74b1798ba1d..8bb0a119ecd48a 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -102,7 +102,7 @@ config ARM_DMA350
config AT_HDMAC
tristate "Atmel AHB DMA support"
- depends on ARCH_AT91
+ depends on ARCH_AT91 || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
@@ -143,7 +143,7 @@ config BCM_SBA_RAID
config DMA_BCM2835
tristate "BCM2835 DMA engine support"
- depends on ARCH_BCM2835
+ depends on ARCH_BCM2835 || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 2d147712cbc69b..7d226453961f82 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -887,7 +887,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
first = xt->sgl;
dev_info(chan2dev(chan),
- "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
+ "%s: src=%pad, dest=%pad, numf=%zu, frame_size=%zu, flags=0x%lx\n",
__func__, &xt->src_start, &xt->dst_start, xt->numf,
xt->frame_size, flags);
@@ -1174,7 +1174,7 @@ atc_prep_dma_memset_sg(struct dma_chan *chan,
int i;
int ret;
- dev_vdbg(chan2dev(chan), "%s: v0x%x l0x%zx f0x%lx\n", __func__,
+ dev_vdbg(chan2dev(chan), "%s: v0x%x l0x%x f0x%lx\n", __func__,
value, sg_len, flags);
if (unlikely(!sgl || !sg_len)) {
@@ -1503,7 +1503,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
unsigned int periods = buf_len / period_len;
unsigned int i;
- dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@%pad - %d (%d/%d)\n",
+ dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@%pad - %d (%zu/%zu)\n",
direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE",
&buf_addr,
periods, buf_len, period_len);
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 0117bb2e8591be..321748e2983e5d 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -1060,7 +1060,6 @@ static struct platform_driver bcm2835_dma_driver = {
module_platform_driver(bcm2835_dma_driver);
-MODULE_ALIAS("platform:bcm2835-dma");
MODULE_DESCRIPTION("BCM2835 DMA engine driver");
MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
MODULE_LICENSE("GPL");
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index cee56cd31a611c..c63fa52036d7ff 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -21,8 +21,6 @@
#include "internal.h"
-#define DRV_NAME "dw_dmac"
-
static int dw_probe(struct platform_device *pdev)
{
const struct dw_dma_chip_pdata *match;
@@ -190,7 +188,7 @@ static struct platform_driver dw_driver = {
.remove = dw_remove,
.shutdown = dw_shutdown,
.driver = {
- .name = DRV_NAME,
+ .name = "dw_dmac",
.pm = pm_sleep_ptr(&dw_dev_pm_ops),
.of_match_table = of_match_ptr(dw_dma_of_id_table),
.acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
@@ -211,4 +209,3 @@ module_exit(dw_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index 4976d7dde08090..a5921275802996 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -206,15 +206,19 @@ void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable);
}
-static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
+static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth src_addr_width,
+ enum dma_slave_buswidth dst_addr_width)
{
- u32 val;
+ u32 src_val, dst_val;
- if (addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
- addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+ src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+ dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- val = ffs(addr_width) - 1;
- return val | (val << 8);
+ src_val = ffs(src_addr_width) - 1;
+ dst_val = ffs(dst_addr_width) - 1;
+ return dst_val | (src_val << 8);
}
void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
@@ -612,13 +616,19 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
dma_buf_next = dma_addr;
if (direction == DMA_MEM_TO_DEV) {
+ if (!fsl_chan->cfg.src_addr_width)
+ fsl_chan->cfg.src_addr_width = fsl_chan->cfg.dst_addr_width;
fsl_chan->attr =
- fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width);
+ fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
+ fsl_chan->cfg.dst_addr_width);
nbytes = fsl_chan->cfg.dst_addr_width *
fsl_chan->cfg.dst_maxburst;
} else {
+ if (!fsl_chan->cfg.dst_addr_width)
+ fsl_chan->cfg.dst_addr_width = fsl_chan->cfg.src_addr_width;
fsl_chan->attr =
- fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width);
+ fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
+ fsl_chan->cfg.dst_addr_width);
nbytes = fsl_chan->cfg.src_addr_width *
fsl_chan->cfg.src_maxburst;
}
@@ -689,13 +699,19 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
fsl_desc->dirn = direction;
if (direction == DMA_MEM_TO_DEV) {
+ if (!fsl_chan->cfg.src_addr_width)
+ fsl_chan->cfg.src_addr_width = fsl_chan->cfg.dst_addr_width;
fsl_chan->attr =
- fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width);
+ fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
+ fsl_chan->cfg.dst_addr_width);
nbytes = fsl_chan->cfg.dst_addr_width *
fsl_chan->cfg.dst_maxburst;
} else {
+ if (!fsl_chan->cfg.dst_addr_width)
+ fsl_chan->cfg.dst_addr_width = fsl_chan->cfg.src_addr_width;
fsl_chan->attr =
- fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width);
+ fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
+ fsl_chan->cfg.dst_addr_width);
nbytes = fsl_chan->cfg.src_addr_width *
fsl_chan->cfg.src_maxburst;
}
@@ -766,6 +782,10 @@ struct dma_async_tx_descriptor *fsl_edma_prep_memcpy(struct dma_chan *chan,
{
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
struct fsl_edma_desc *fsl_desc;
+ u32 src_bus_width, dst_bus_width;
+
+ src_bus_width = min_t(u32, DMA_SLAVE_BUSWIDTH_32_BYTES, 1 << (ffs(dma_src) - 1));
+ dst_bus_width = min_t(u32, DMA_SLAVE_BUSWIDTH_32_BYTES, 1 << (ffs(dma_dst) - 1));
fsl_desc = fsl_edma_alloc_desc(fsl_chan, 1);
if (!fsl_desc)
@@ -778,8 +798,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_memcpy(struct dma_chan *chan,
/* To match with copy_align and max_seg_size so 1 tcd is enough */
fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[0].vtcd, dma_src, dma_dst,
- fsl_edma_get_tcd_attr(DMA_SLAVE_BUSWIDTH_32_BYTES),
- 32, len, 0, 1, 1, 32, 0, true, true, false);
+ fsl_edma_get_tcd_attr(src_bus_width, dst_bus_width),
+ src_bus_width, len, 0, 1, 1, dst_bus_width, 0, true,
+ true, false);
return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
}
diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
index 97583c7d51a2e8..a753b7cbfa7a33 100644
--- a/drivers/dma/fsl-edma-main.c
+++ b/drivers/dma/fsl-edma-main.c
@@ -999,6 +999,5 @@ static void __exit fsl_edma_exit(void)
}
module_exit(fsl_edma_exit);
-MODULE_ALIAS("platform:fsl-edma");
MODULE_DESCRIPTION("Freescale eDMA engine driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c
index 21e13f1207cbe6..6ace5bf80c40be 100644
--- a/drivers/dma/fsl-qdma.c
+++ b/drivers/dma/fsl-qdma.c
@@ -1296,6 +1296,5 @@ static struct platform_driver fsl_qdma_driver = {
module_platform_driver(fsl_qdma_driver);
-MODULE_ALIAS("platform:fsl-qdma");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("NXP Layerscape qDMA engine driver");
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index 5cf419fe6b4645..c2cdf41b6e5764 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -16,6 +16,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
u32 *status);
static void idxd_device_wqs_clear_state(struct idxd_device *idxd);
static void idxd_wq_disable_cleanup(struct idxd_wq *wq);
+static int idxd_wq_config_write(struct idxd_wq *wq);
/* Interrupt control bits */
void idxd_unmask_error_interrupts(struct idxd_device *idxd)
@@ -215,14 +216,28 @@ int idxd_wq_disable(struct idxd_wq *wq, bool reset_config)
return 0;
}
+ /*
+ * Disable WQ does not drain address translations, if WQ attributes are
+ * changed before translations are drained, pending translations can
+ * be issued using updated WQ attibutes, resulting in invalid
+ * translations being cached in the device translation cache.
+ *
+ * To make sure pending translations are drained before WQ
+ * attributes are changed, we use a WQ Drain followed by WQ Reset and
+ * then restore the WQ configuration.
+ */
+ idxd_wq_drain(wq);
+
operand = BIT(wq->id % 16) | ((wq->id / 16) << 16);
- idxd_cmd_exec(idxd, IDXD_CMD_DISABLE_WQ, operand, &status);
+ idxd_cmd_exec(idxd, IDXD_CMD_RESET_WQ, operand, &status);
if (status != IDXD_CMDSTS_SUCCESS) {
- dev_dbg(dev, "WQ disable failed: %#x\n", status);
+ dev_dbg(dev, "WQ reset failed: %#x\n", status);
return -ENXIO;
}
+ idxd_wq_config_write(wq);
+
if (reset_config)
idxd_wq_disable_cleanup(wq);
clear_bit(wq->id, idxd->wq_enable_map);
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index acc2983e28e0dd..0f9cd7815f880e 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -1034,5 +1034,4 @@ static struct platform_driver k3_pdma_driver = {
module_platform_driver(k3_pdma_driver);
MODULE_DESCRIPTION("HiSilicon k3 DMA Driver");
-MODULE_ALIAS("platform:k3dma");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index b7fb843c67a6f2..ba03321eeff799 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -554,8 +554,7 @@ static void mmp_tdma_issue_pending(struct dma_chan *chan)
static void mmp_tdma_remove(struct platform_device *pdev)
{
- if (pdev->dev.of_node)
- of_dma_controller_free(pdev->dev.of_node);
+ of_dma_controller_free(pdev->dev.of_node);
}
static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
@@ -743,6 +742,5 @@ module_platform_driver(mmp_tdma_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MMP Two-Channel DMA Driver");
-MODULE_ALIAS("platform:mmp-tdma");
MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>");
diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index 765462303de098..334425faac00bf 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -1500,7 +1500,6 @@ static const struct platform_device_id nbpf_ids[] = {
};
MODULE_DEVICE_TABLE(platform, nbpf_ids);
-#ifdef CONFIG_PM
static int nbpf_runtime_suspend(struct device *dev)
{
struct nbpf_device *nbpf = dev_get_drvdata(dev);
@@ -1513,17 +1512,16 @@ static int nbpf_runtime_resume(struct device *dev)
struct nbpf_device *nbpf = dev_get_drvdata(dev);
return clk_prepare_enable(nbpf->clk);
}
-#endif
static const struct dev_pm_ops nbpf_pm_ops = {
- SET_RUNTIME_PM_OPS(nbpf_runtime_suspend, nbpf_runtime_resume, NULL)
+ RUNTIME_PM_OPS(nbpf_runtime_suspend, nbpf_runtime_resume, NULL)
};
static struct platform_driver nbpf_driver = {
.driver = {
.name = "dma-nbpf",
.of_match_table = nbpf_match,
- .pm = &nbpf_pm_ops,
+ .pm = pm_ptr(&nbpf_pm_ops),
},
.id_table = nbpf_ids,
.probe = nbpf_probe,
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index 8e87738086b25a..66bfea1f156d1e 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -1619,7 +1619,8 @@ gpi_peripheral_config(struct dma_chan *chan, struct dma_slave_config *config)
}
static int gpi_create_i2c_tre(struct gchan *chan, struct gpi_desc *desc,
- struct scatterlist *sgl, enum dma_transfer_direction direction)
+ struct scatterlist *sgl, enum dma_transfer_direction direction,
+ unsigned long flags)
{
struct gpi_i2c_config *i2c = chan->config;
struct device *dev = chan->gpii->gpi_dev->dev;
@@ -1684,6 +1685,9 @@ static int gpi_create_i2c_tre(struct gchan *chan, struct gpi_desc *desc,
tre->dword[3] = u32_encode_bits(TRE_TYPE_DMA, TRE_FLAGS_TYPE);
tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_IEOT);
+
+ if (!(flags & DMA_PREP_INTERRUPT))
+ tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_BEI);
}
for (i = 0; i < tre_idx; i++)
@@ -1827,6 +1831,9 @@ gpi_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
return NULL;
}
+ if (!(flags & DMA_PREP_INTERRUPT) && (nr - nr_tre < 2))
+ return NULL;
+
gpi_desc = kzalloc(sizeof(*gpi_desc), GFP_NOWAIT);
if (!gpi_desc)
return NULL;
@@ -1835,7 +1842,7 @@ gpi_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (gchan->protocol == QCOM_GPI_SPI) {
i = gpi_create_spi_tre(gchan, gpi_desc, sgl, direction);
} else if (gchan->protocol == QCOM_GPI_I2C) {
- i = gpi_create_i2c_tre(gchan, gpi_desc, sgl, direction);
+ i = gpi_create_i2c_tre(gchan, gpi_desc, sgl, direction, flags);
} else {
dev_err(dev, "invalid peripheral: %d\n", gchan->protocol);
kfree(gpi_desc);
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index 8184d475a49a18..a16c7e83bd14ac 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -50,7 +50,7 @@ config RENESAS_USB_DMAC
config RZ_DMAC
tristate "Renesas RZ DMA Controller"
- depends on ARCH_R7S72100 || ARCH_RZG2L || COMPILE_TEST
+ depends on ARCH_RENESAS || COMPILE_TEST
select RENESAS_DMA
select DMA_VIRTUAL_CHANNELS
help
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 0c45ce8c74aa2d..475a347cae1b6a 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -1728,19 +1728,12 @@ static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec,
* Power management
*/
-#ifdef CONFIG_PM
-static int rcar_dmac_runtime_suspend(struct device *dev)
-{
- return 0;
-}
-
static int rcar_dmac_runtime_resume(struct device *dev)
{
struct rcar_dmac *dmac = dev_get_drvdata(dev);
return rcar_dmac_init(dmac);
}
-#endif
static const struct dev_pm_ops rcar_dmac_pm = {
/*
@@ -1748,10 +1741,9 @@ static const struct dev_pm_ops rcar_dmac_pm = {
* - Wait for the current transfer to complete and stop the device,
* - Resume transfers, if any.
*/
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(rcar_dmac_runtime_suspend, rcar_dmac_runtime_resume,
- NULL)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ RUNTIME_PM_OPS(NULL, rcar_dmac_runtime_resume, NULL)
};
/* -----------------------------------------------------------------------------
@@ -2036,7 +2028,7 @@ MODULE_DEVICE_TABLE(of, rcar_dmac_of_ids);
static struct platform_driver rcar_dmac_driver = {
.driver = {
- .pm = &rcar_dmac_pm,
+ .pm = pm_ptr(&rcar_dmac_pm),
.name = "rcar-dmac",
.of_match_table = rcar_dmac_of_ids,
},
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 7e2b6c97fa2f97..b42e5a66fd9575 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -670,7 +670,6 @@ static struct dma_chan *usb_dmac_of_xlate(struct of_phandle_args *dma_spec,
* Power management
*/
-#ifdef CONFIG_PM
static int usb_dmac_runtime_suspend(struct device *dev)
{
struct usb_dmac *dmac = dev_get_drvdata(dev);
@@ -691,13 +690,11 @@ static int usb_dmac_runtime_resume(struct device *dev)
return usb_dmac_init(dmac);
}
-#endif /* CONFIG_PM */
static const struct dev_pm_ops usb_dmac_pm = {
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(usb_dmac_runtime_suspend, usb_dmac_runtime_resume,
- NULL)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ RUNTIME_PM_OPS(usb_dmac_runtime_suspend, usb_dmac_runtime_resume, NULL)
};
/* -----------------------------------------------------------------------------
@@ -894,7 +891,7 @@ MODULE_DEVICE_TABLE(of, usb_dmac_of_ids);
static struct platform_driver usb_dmac_driver = {
.driver = {
- .pm = &usb_dmac_pm,
+ .pm = pm_ptr(&usb_dmac_pm),
.name = "usb-dmac",
.of_match_table = usb_dmac_of_ids,
},
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index 187a090463cedf..6207e0b185e1d5 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -1311,4 +1311,3 @@ MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("DMA driver for Spreadtrum");
MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>");
MODULE_AUTHOR("Eric Long <eric.long@spreadtrum.com>");
-MODULE_ALIAS("platform:sprd-dma");
diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c
index c65ee0c7bfbdb2..dc2ab7d16cf2ae 100644
--- a/drivers/dma/st_fdma.c
+++ b/drivers/dma/st_fdma.c
@@ -866,4 +866,3 @@ MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("STMicroelectronics FDMA engine driver");
MODULE_AUTHOR("Ludovic.barre <Ludovic.barre@st.com>");
MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
index fad896ff29a2d3..d0e8bb27a03b87 100644
--- a/drivers/dma/tegra210-adma.c
+++ b/drivers/dma/tegra210-adma.c
@@ -1230,7 +1230,6 @@ static struct platform_driver tegra_admac_driver = {
module_platform_driver(tegra_admac_driver);
-MODULE_ALIAS("platform:tegra210-adma");
MODULE_DESCRIPTION("NVIDIA Tegra ADMA driver");
MODULE_AUTHOR("Dara Ramesh <dramesh@nvidia.com>");
MODULE_AUTHOR("Jon Hunter <jonathanh@nvidia.com>");
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 43fdd89b8bebc8..3a04016db2c322 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -77,6 +77,25 @@ enum geni_i2c_err_code {
#define XFER_TIMEOUT HZ
#define RST_TIMEOUT HZ
+#define QCOM_I2C_MIN_NUM_OF_MSGS_MULTI_DESC 2
+
+/**
+ * struct geni_i2c_gpi_multi_desc_xfer - Structure for multi transfer support
+ *
+ * @msg_idx_cnt: Current message index being processed in the transfer
+ * @unmap_msg_cnt: Number of messages that have been unmapped
+ * @irq_cnt: Number of transfer completion interrupts received
+ * @dma_buf: Array of virtual addresses for DMA-safe buffers
+ * @dma_addr: Array of DMA addresses corresponding to the buffers
+ */
+struct geni_i2c_gpi_multi_desc_xfer {
+ u32 msg_idx_cnt;
+ u32 unmap_msg_cnt;
+ u32 irq_cnt;
+ void **dma_buf;
+ dma_addr_t *dma_addr;
+};
+
struct geni_i2c_dev {
struct geni_se se;
u32 tx_wm;
@@ -99,6 +118,9 @@ struct geni_i2c_dev {
struct dma_chan *rx_c;
bool gpi_mode;
bool abort_done;
+ bool is_tx_multi_desc_xfer;
+ u32 num_msgs;
+ struct geni_i2c_gpi_multi_desc_xfer i2c_multi_desc_config;
};
struct geni_i2c_desc {
@@ -499,6 +521,7 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result)
{
struct geni_i2c_dev *gi2c = cb;
+ struct geni_i2c_gpi_multi_desc_xfer *tx_multi_xfer;
if (result->result != DMA_TRANS_NOERROR) {
dev_err(gi2c->se.dev, "DMA txn failed:%d\n", result->result);
@@ -507,6 +530,11 @@ static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result)
dev_dbg(gi2c->se.dev, "DMA xfer has pending: %d\n", result->residue);
}
+ if (gi2c->is_tx_multi_desc_xfer) {
+ tx_multi_xfer = &gi2c->i2c_multi_desc_config;
+ tx_multi_xfer->irq_cnt++;
+ }
+
complete(&gi2c->done);
}
@@ -525,7 +553,72 @@ static void geni_i2c_gpi_unmap(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
}
}
-static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
+/**
+ * geni_i2c_gpi_multi_desc_unmap() - Unmaps DMA buffers post multi message TX transfers
+ * @gi2c: I2C dev handle
+ * @msgs: Array of I2C messages
+ * @peripheral: Pointer to gpi_i2c_config
+ */
+static void geni_i2c_gpi_multi_desc_unmap(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
+ struct gpi_i2c_config *peripheral)
+{
+ u32 msg_xfer_cnt, wr_idx = 0;
+ struct geni_i2c_gpi_multi_desc_xfer *tx_multi_xfer = &gi2c->i2c_multi_desc_config;
+
+ msg_xfer_cnt = gi2c->err ? tx_multi_xfer->msg_idx_cnt : tx_multi_xfer->irq_cnt;
+
+ /* Unmap the processed DMA buffers based on the received interrupt count */
+ for (; tx_multi_xfer->unmap_msg_cnt < msg_xfer_cnt; tx_multi_xfer->unmap_msg_cnt++) {
+ wr_idx = tx_multi_xfer->unmap_msg_cnt;
+ geni_i2c_gpi_unmap(gi2c, &msgs[wr_idx],
+ tx_multi_xfer->dma_buf[wr_idx],
+ tx_multi_xfer->dma_addr[wr_idx],
+ NULL, 0);
+
+ if (tx_multi_xfer->unmap_msg_cnt == gi2c->num_msgs - 1) {
+ kfree(tx_multi_xfer->dma_buf);
+ kfree(tx_multi_xfer->dma_addr);
+ break;
+ }
+ }
+}
+
+/**
+ * geni_i2c_gpi_multi_xfer_timeout_handler() - Handles multi message transfer timeout
+ * @dev: Pointer to the corresponding dev node
+ * @multi_xfer: Pointer to the geni_i2c_gpi_multi_desc_xfer
+ * @transfer_timeout_msecs: Timeout value in milliseconds
+ * @transfer_comp: Completion object of the transfer
+ *
+ * This function waits for the completion of each processed transfer messages
+ * based on the interrupts generated upon transfer completion.
+ *
+ * Return: On success returns 0, -ETIMEDOUT on timeout.
+ */
+static int geni_i2c_gpi_multi_xfer_timeout_handler(struct device *dev,
+ struct geni_i2c_gpi_multi_desc_xfer *multi_xfer,
+ u32 transfer_timeout_msecs,
+ struct completion *transfer_comp)
+{
+ int i;
+ u32 time_left;
+
+ for (i = 0; i < multi_xfer->msg_idx_cnt - 1; i++) {
+ reinit_completion(transfer_comp);
+
+ if (multi_xfer->msg_idx_cnt != multi_xfer->irq_cnt) {
+ time_left = wait_for_completion_timeout(transfer_comp,
+ transfer_timeout_msecs);
+ if (!time_left) {
+ dev_err(dev, "%s: Transfer timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+ }
+ return 0;
+}
+
+static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
struct dma_slave_config *config, dma_addr_t *dma_addr_p,
void **buf, unsigned int op, struct dma_chan *dma_chan)
{
@@ -537,26 +630,45 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
enum dma_transfer_direction dma_dirn;
struct dma_async_tx_descriptor *desc;
int ret;
+ struct geni_i2c_gpi_multi_desc_xfer *gi2c_gpi_xfer;
+ dma_cookie_t cookie;
+ u32 msg_idx;
peripheral = config->peripheral_config;
+ gi2c_gpi_xfer = &gi2c->i2c_multi_desc_config;
+ msg_idx = gi2c_gpi_xfer->msg_idx_cnt;
- dma_buf = i2c_get_dma_safe_msg_buf(msg, 1);
- if (!dma_buf)
- return -ENOMEM;
+ dma_buf = i2c_get_dma_safe_msg_buf(&msgs[msg_idx], 1);
+ if (!dma_buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
if (op == I2C_WRITE)
map_dirn = DMA_TO_DEVICE;
else
map_dirn = DMA_FROM_DEVICE;
- addr = dma_map_single(gi2c->se.dev->parent, dma_buf, msg->len, map_dirn);
+ addr = dma_map_single(gi2c->se.dev->parent, dma_buf,
+ msgs[msg_idx].len, map_dirn);
if (dma_mapping_error(gi2c->se.dev->parent, addr)) {
- i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
- return -ENOMEM;
+ i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (gi2c->is_tx_multi_desc_xfer) {
+ flags = DMA_CTRL_ACK;
+
+ /* BEI bit to be cleared for last TRE */
+ if (msg_idx == gi2c->num_msgs - 1)
+ flags |= DMA_PREP_INTERRUPT;
+ } else {
+ flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
}
/* set the length as message for rx txn */
- peripheral->rx_len = msg->len;
+ peripheral->rx_len = msgs[msg_idx].len;
peripheral->op = op;
ret = dmaengine_slave_config(dma_chan, config);
@@ -567,14 +679,21 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
peripheral->set_config = 0;
peripheral->multi_msg = true;
- flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
if (op == I2C_WRITE)
dma_dirn = DMA_MEM_TO_DEV;
else
dma_dirn = DMA_DEV_TO_MEM;
- desc = dmaengine_prep_slave_single(dma_chan, addr, msg->len, dma_dirn, flags);
+ desc = dmaengine_prep_slave_single(dma_chan, addr, msgs[msg_idx].len,
+ dma_dirn, flags);
+ if (!desc && !(flags & DMA_PREP_INTERRUPT)) {
+ /* Retry with interrupt if not enough TREs */
+ flags |= DMA_PREP_INTERRUPT;
+ desc = dmaengine_prep_slave_single(dma_chan, addr, msgs[msg_idx].len,
+ dma_dirn, flags);
+ }
+
if (!desc) {
dev_err(gi2c->se.dev, "prep_slave_sg failed\n");
ret = -EIO;
@@ -584,15 +703,48 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
desc->callback_result = i2c_gpi_cb_result;
desc->callback_param = gi2c;
- dmaengine_submit(desc);
- *buf = dma_buf;
- *dma_addr_p = addr;
+ if (!((msgs[msg_idx].flags & I2C_M_RD) && op == I2C_WRITE))
+ gi2c_gpi_xfer->msg_idx_cnt++;
+ cookie = dmaengine_submit(desc);
+ if (dma_submit_error(cookie)) {
+ dev_err(gi2c->se.dev,
+ "%s: dmaengine_submit failed (%d)\n", __func__, cookie);
+ ret = -EINVAL;
+ goto err_config;
+ }
+
+ if (gi2c->is_tx_multi_desc_xfer) {
+ gi2c_gpi_xfer->dma_buf[msg_idx] = dma_buf;
+ gi2c_gpi_xfer->dma_addr[msg_idx] = addr;
+
+ dma_async_issue_pending(gi2c->tx_c);
+
+ if ((msg_idx == (gi2c->num_msgs - 1)) || flags & DMA_PREP_INTERRUPT) {
+ ret = geni_i2c_gpi_multi_xfer_timeout_handler(gi2c->se.dev, gi2c_gpi_xfer,
+ XFER_TIMEOUT, &gi2c->done);
+ if (ret) {
+ dev_err(gi2c->se.dev,
+ "I2C multi write msg transfer timeout: %d\n",
+ ret);
+ gi2c->err = ret;
+ return ret;
+ }
+ }
+ } else {
+ /* Non multi descriptor message transfer */
+ *buf = dma_buf;
+ *dma_addr_p = addr;
+ }
return 0;
err_config:
- dma_unmap_single(gi2c->se.dev->parent, addr, msg->len, map_dirn);
- i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
+ dma_unmap_single(gi2c->se.dev->parent, addr,
+ msgs[msg_idx].len, map_dirn);
+ i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false);
+
+out:
+ gi2c->err = ret;
return ret;
}
@@ -604,6 +756,7 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
unsigned long time_left;
dma_addr_t tx_addr, rx_addr;
void *tx_buf = NULL, *rx_buf = NULL;
+ struct geni_i2c_gpi_multi_desc_xfer *tx_multi_xfer;
const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
config.peripheral_config = &peripheral;
@@ -617,6 +770,41 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
peripheral.set_config = 1;
peripheral.multi_msg = false;
+ gi2c->num_msgs = num;
+ gi2c->is_tx_multi_desc_xfer = false;
+
+ tx_multi_xfer = &gi2c->i2c_multi_desc_config;
+ memset(tx_multi_xfer, 0, sizeof(struct geni_i2c_gpi_multi_desc_xfer));
+
+ /*
+ * If number of write messages are two and higher then
+ * configure hardware for multi descriptor transfers with BEI.
+ */
+ if (num >= QCOM_I2C_MIN_NUM_OF_MSGS_MULTI_DESC) {
+ gi2c->is_tx_multi_desc_xfer = true;
+ for (i = 0; i < num; i++) {
+ if (msgs[i].flags & I2C_M_RD) {
+ /*
+ * Multi descriptor transfer with BEI
+ * support is enabled for write transfers.
+ * TODO: Add BEI optimization support for
+ * read transfers later.
+ */
+ gi2c->is_tx_multi_desc_xfer = false;
+ break;
+ }
+ }
+ }
+
+ if (gi2c->is_tx_multi_desc_xfer) {
+ tx_multi_xfer->dma_buf = kcalloc(num, sizeof(void *), GFP_KERNEL);
+ tx_multi_xfer->dma_addr = kcalloc(num, sizeof(dma_addr_t), GFP_KERNEL);
+ if (!tx_multi_xfer->dma_buf || !tx_multi_xfer->dma_addr) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
+
for (i = 0; i < num; i++) {
gi2c->cur = &msgs[i];
gi2c->err = 0;
@@ -627,14 +815,16 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
peripheral.stretch = 1;
peripheral.addr = msgs[i].addr;
+ if (i > 0 && (!(msgs[i].flags & I2C_M_RD)))
+ peripheral.multi_msg = false;
- ret = geni_i2c_gpi(gi2c, &msgs[i], &config,
+ ret = geni_i2c_gpi(gi2c, msgs, &config,
&tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c);
if (ret)
goto err;
if (msgs[i].flags & I2C_M_RD) {
- ret = geni_i2c_gpi(gi2c, &msgs[i], &config,
+ ret = geni_i2c_gpi(gi2c, msgs, &config,
&rx_addr, &rx_buf, I2C_READ, gi2c->rx_c);
if (ret)
goto err;
@@ -642,18 +832,24 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
dma_async_issue_pending(gi2c->rx_c);
}
- dma_async_issue_pending(gi2c->tx_c);
-
- time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
- if (!time_left)
- gi2c->err = -ETIMEDOUT;
+ if (!gi2c->is_tx_multi_desc_xfer) {
+ dma_async_issue_pending(gi2c->tx_c);
+ time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
+ if (!time_left) {
+ dev_err(gi2c->se.dev, "%s:I2C timeout\n", __func__);
+ gi2c->err = -ETIMEDOUT;
+ }
+ }
if (gi2c->err) {
ret = gi2c->err;
goto err;
}
- geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
+ if (!gi2c->is_tx_multi_desc_xfer)
+ geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
+ else if (tx_multi_xfer->unmap_msg_cnt != tx_multi_xfer->irq_cnt)
+ geni_i2c_gpi_multi_desc_unmap(gi2c, msgs, &peripheral);
}
return num;
@@ -662,7 +858,11 @@ err:
dev_err(gi2c->se.dev, "GPI transfer failed: %d\n", ret);
dmaengine_terminate_sync(gi2c->rx_c);
dmaengine_terminate_sync(gi2c->tx_c);
- geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
+ if (gi2c->is_tx_multi_desc_xfer)
+ geni_i2c_gpi_multi_desc_unmap(gi2c, msgs, &peripheral);
+ else
+ geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
+
return ret;
}