From b46d155e0db3b98a531431357247e15dc357a797 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 4 Sep 2025 17:30:08 +0200 Subject: [PATCH 01/23] dmaengine: sh: usb-dmac: Convert to NOIRQ_SYSTEM_SLEEP/RUNTIME_PM_OPS() Convert the Renesas USB-DMA Controller driver from SET_NOIRQ_SYSTEM_SLEEP_PM_OPS() and SET_RUNTIME_PM_OPS() to NOIRQ_SYSTEM_SLEEP_PM_OPS(), RUNTIME_PM_OPS(), and pm_ptr(). This lets us drop the check for CONFIG_PM, and reduces kernel size in case CONFIG_PM is disabled, while increasing build coverage. Signed-off-by: Geert Uytterhoeven Signed-off-by: Vinod Koul --- drivers/dma/sh/usb-dmac.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index 7e2b6c97fa2f..b42e5a66fd95 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, }, From 75396f5b9534780add6a32aaa9b005911bc98dd2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 4 Sep 2025 17:28:37 +0200 Subject: [PATCH 02/23] dmaengine: nbpfaxi: Convert to RUNTIME_PM_OPS() Convert the Renesas Type-AXI NBPF DMA driver from SET_RUNTIME_PM_OPS() to RUNTIME_PM_OPS(), and pm_ptr(). This lets us drop the check for CONFIG_PM, and reduces kernel size in case CONFIG_PM is disabled, while increasing build coverage. Signed-off-by: Geert Uytterhoeven Signed-off-by: Vinod Koul --- drivers/dma/nbpfaxi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c index 765462303de0..334425faac00 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, From b78c6286acd7ef93ddb064b5ad08b993eab33482 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 4 Sep 2025 17:25:09 +0200 Subject: [PATCH 03/23] dmaengine: rcar-dmac: Remove dummy Runtime PM callback Since commit 63d00be69348fda4 ("PM: runtime: Allow unassigned ->runtime_suspend|resume callbacks"), unassigned .runtime_{suspend,resume}() callbacks are treated the same as dummy callbacks that just return zero. Signed-off-by: Geert Uytterhoeven Signed-off-by: Vinod Koul --- drivers/dma/sh/rcar-dmac.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 0c45ce8c74aa..0b8fb830ce8c 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -1729,11 +1729,6 @@ static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec, */ #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); @@ -1750,8 +1745,7 @@ static const struct dev_pm_ops rcar_dmac_pm = { */ 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) + SET_RUNTIME_PM_OPS(NULL, rcar_dmac_runtime_resume, NULL) }; /* ----------------------------------------------------------------------------- From c3c328d2383fa7f68ec93574152924cd8f5fe82c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 4 Sep 2025 17:25:10 +0200 Subject: [PATCH 04/23] dmaengine: rcar-dmac: Convert to NOIRQ_SYSTEM_SLEEP/RUNTIME_PM_OPS() Convert the Renesas R-Car DMA Controller driver from SET_NOIRQ_SYSTEM_SLEEP_PM_OPS() and SET_RUNTIME_PM_OPS() to NOIRQ_SYSTEM_SLEEP_PM_OPS(), RUNTIME_PM_OPS(), and pm_ptr(). This lets us drop the check for CONFIG_PM, and reduces kernel size in case CONFIG_PM is disabled, while increasing build coverage. Signed-off-by: Geert Uytterhoeven Signed-off-by: Vinod Koul --- drivers/dma/sh/rcar-dmac.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 0b8fb830ce8c..475a347cae1b 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -1728,14 +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_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 = { /* @@ -1743,9 +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(NULL, 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) }; /* ----------------------------------------------------------------------------- @@ -2030,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, }, From bc2c39600212979b6fc836113bde1b707c02f442 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 2 Oct 2025 13:47:35 +0100 Subject: [PATCH 05/23] dmaengine: sh: Kconfig: Drop ARCH_R7S72100/ARCH_RZG2L dependency The RZ DMA controller is used across multiple Renesas SoCs, not only RZ/A1 (R7S72100) and RZ/G2L. Limiting the build to these SoCs prevents enabling the driver on newer platforms such as RZ/V2H(P) and RZ/V2N. Replace the ARCH_R7S72100 || ARCH_RZG2L dependency with ARCH_RENESAS so the driver can be built for all Renesas SoCs. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Signed-off-by: Vinod Koul --- drivers/dma/sh/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig index 8184d475a49a..a16c7e83bd14 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 From f80ea8566917c4bb680911db839a170873e5d17c Mon Sep 17 00:00:00 2001 From: Nikhil Rao Date: Tue, 30 Sep 2025 18:22:26 -0700 Subject: [PATCH 06/23] dmaengine: idxd: drain ATS translations when disabling WQ There's an errata[1], for the Disable WQ command that it does not guaranteee that address translations are drained. If WQ configuration is updated, pending address translations can use an updated WQ configuration, resulting an invalid translation response that is cached in the device translation cache. Replace the Disable WQ command with a Drain WQ command followed by a Reset WQ command, this guarantees that all ATS translations are drained from the device before changing WQ configuration. [1] https://cdrdv2.intel.com/v1/dl/getcontent/843306 ("Intel DSA May Cause Invalid Translation Caching") Signed-off-by: Nikhil Rao Signed-off-by: Fenghua Yu Signed-off-by: Vinicius Costa Gomes Reviewed-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 5cf419fe6b46..c2cdf41b6e57 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); From 4e8331317e73902e8b2663352c8766227e633901 Mon Sep 17 00:00:00 2001 From: Jyothi Kumar Seerapu Date: Thu, 25 Sep 2025 17:30:34 +0530 Subject: [PATCH 07/23] dmaengine: qcom: gpi: Add GPI Block event interrupt support GSI hardware generates an interrupt for each transfer completion. For multiple messages within a single transfer, this results in N interrupts for N messages, leading to significant software interrupt latency. To mitigate this latency, utilize Block Event Interrupt (BEI) mechanism. Enabling BEI instructs the GSI hardware to prevent interrupt generation and BEI is disabled when an interrupt is necessary. Large I2C transfer can be divided into chunks of messages internally. Interrupts are not expected for the messages for which BEI bit set, only the last message triggers an interrupt, indicating the completion of N messages. This BEI mechanism enhances overall transfer efficiency. Signed-off-by: Jyothi Kumar Seerapu Reviewed-by: Dmitry Baryshkov Signed-off-by: Vinod Koul --- drivers/dma/qcom/gpi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 8e87738086b2..66bfea1f156d 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); From 398035178503bf662281bbffb4bebce1460a4bc5 Mon Sep 17 00:00:00 2001 From: Jyothi Kumar Seerapu Date: Thu, 25 Sep 2025 17:30:35 +0530 Subject: [PATCH 08/23] i2c: i2c-qcom-geni: Add Block event interrupt support The I2C driver gets an interrupt upon transfer completion. When handling multiple messages in a single transfer, this results in N interrupts for N messages, leading to significant software interrupt latency. To mitigate this latency, utilize Block Event Interrupt (BEI) mechanism. Enabling BEI instructs the hardware to prevent interrupt generation and BEI is disabled when an interrupt is necessary. Large I2C transfer can be divided into chunks of messages internally. Interrupts are not expected for the messages for which BEI bit set, only the last message triggers an interrupt, indicating the completion of N messages. This BEI mechanism enhances overall transfer efficiency. BEI optimizations are currently implemented for I2C write transfers only, as there is no use case for multiple I2C read messages in a single transfer at this time. Signed-off-by: Jyothi Kumar Seerapu Reviewed-by: Dmitry Baryshkov Acked-by: Andi Shyti Reviewed-by: Mukesh Savaliya Acked-by: Mukesh Savaliya Signed-off-by: Vinod Koul --- drivers/i2c/busses/i2c-qcom-geni.c | 248 ++++++++++++++++++++++++++--- 1 file changed, 224 insertions(+), 24 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 95a577764d5c..962780d76e07 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; } From 938eae912ac52f8e9e5f2463e2db30cfe6f895d5 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 5 Nov 2025 18:24:04 -0800 Subject: [PATCH 09/23] dmaengine: at_hdmac: fix formats under 64-bit size_t formats under 32-bit evaluate to the same thing and GCC does not warn against it. Not the case with 64-bit. Signed-off-by: Rosen Penev Reviewed-by: Eugen Hristev Link: https://patch.msgid.link/20251106022405.85604-2-rosenp@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 2d147712cbc6..7d226453961f 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); From 5d8c5bea0da97809813b5f702700019cfffb6085 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 5 Nov 2025 18:24:05 -0800 Subject: [PATCH 10/23] dmaengine: at_hdmac: add COMPILE_TEST support Allows the buildbot to detect potential issues with the code on various platforms. Signed-off-by: Rosen Penev Reviewed-by: Eugen Hristev Link: https://patch.msgid.link/20251106022405.85604-3-rosenp@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index b8a74b1798ba..c06327be8268 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 From bfab38bee5652f335c5d693d54eb61bc25850518 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:45:16 +0100 Subject: [PATCH 11/23] dmaengine: bcm2835: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251120114524.8431-2-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/bcm2835-dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 0117bb2e8591..321748e2983e 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 "); MODULE_LICENSE("GPL"); From 660c40702d9073035c61a9573b299481b9c7f3cd Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:45:17 +0100 Subject: [PATCH 12/23] dmaengine: dw: drop unused module alias The driver does not support anything but OF and ACPI probe since commit b3757413b91e ("dmaengine: dw: platform: Use struct dw_dma_chip_pdata") so drop the unused platform module alias along with the now unnecessary driver name define. Signed-off-by: Johan Hovold Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20251120114524.8431-3-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/dw/platform.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index cee56cd31a61..c63fa52036d7 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); From 03adb0eb0ed64a1e13e04c0fb57a073896efe6ca Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:45:18 +0100 Subject: [PATCH 13/23] dmaengine: fsl-edma: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Frank Li Link: https://patch.msgid.link/20251120114524.8431-4-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index 97583c7d51a2..a753b7cbfa7a 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"); From 9180a66fb43214ae02311176e43eec361ff80d67 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:45:19 +0100 Subject: [PATCH 14/23] dmaengine: fsl-qdma: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Frank Li Link: https://patch.msgid.link/20251120114524.8431-5-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/fsl-qdma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c index 21e13f1207cb..6ace5bf80c40 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"); From 73b77c3d80031b4636a24912962ffeb295438b0a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:45:20 +0100 Subject: [PATCH 15/23] dmaengine: k3dma: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251120114524.8431-6-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/k3dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index acc2983e28e0..0f9cd7815f88 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"); From 73391fecf23860804bceb6670cef74a3626ecf92 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:45:21 +0100 Subject: [PATCH 16/23] dmaengine: mmp_tdma: drop unused module alias The driver does not support anything but OF probe since commit 3b0f4a54f247 ("dma:mmp_tdma: get sram pool through device tree") so drop the unused platform module alias. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251120114524.8431-7-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/mmp_tdma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index b7fb843c67a6..6186b9dc5457 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -743,6 +743,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 "); MODULE_AUTHOR("Zhangfei Gao "); From 3b7b0bbdcba984287225bb373e52845c23dadb93 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:45:22 +0100 Subject: [PATCH 17/23] dmaengine: mmp_tdma: drop unnecessary OF node check in remove The driver does not support anything but OF probe since commit 3b0f4a54f247 ("dma:mmp_tdma: get sram pool through device tree"). Commit a67ba97dfb30 ("dmaengine: Use device_get_match_data()") later removed most remnants of platform probing except for an unnecessary OF node check in remove(). Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251120114524.8431-8-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/mmp_tdma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 6186b9dc5457..ba03321eeff7 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, From 1911f507a54b42bd01ae30590c06d8140beee424 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:45:23 +0100 Subject: [PATCH 18/23] dmaengine: sprd: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251120114524.8431-9-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 187a090463ce..6207e0b185e1 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 "); MODULE_AUTHOR("Eric Long "); -MODULE_ALIAS("platform:sprd-dma"); From e0aef2a5c33680bbd332e5b5f64afc8dde8d46f6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:45:24 +0100 Subject: [PATCH 19/23] dmaengine: tegra210-adma: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Jon Hunter Link: https://patch.msgid.link/20251120114524.8431-10-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/tegra210-adma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index fad896ff29a2..d0e8bb27a03b 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 "); MODULE_AUTHOR("Jon Hunter "); From d3e1935fba8d71ef1889cbc2d6e2447cb829070f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 12:50:16 +0100 Subject: [PATCH 20/23] dmaengine: bcm2835: enable compile testing There seems to be nothing preventing the driver from being compile tested so enable that for wider build coverage. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251120115016.8967-1-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index c06327be8268..8bb0a119ecd4 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -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 From cd3ba117688f7694f000293fd5c034f9f842dbb2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 20 Nov 2025 17:49:07 +0100 Subject: [PATCH 21/23] dmaengine: st_fdma: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251120164907.28007-1-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/st_fdma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c index c65ee0c7bfbd..dc2ab7d16cf2 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 "); MODULE_AUTHOR("Peter Griffin "); -MODULE_ALIAS("platform:" DRIVER_NAME); From 1ecd8b6016c07da162175c708666762e058a0b29 Mon Sep 17 00:00:00 2001 From: Han Xu Date: Wed, 19 Nov 2025 10:32:55 -0600 Subject: [PATCH 22/23] dmaengine: fsl-edma: configure tcd attr with separate src and dst settings Set the edma tcd transfer attribution settings for the src and dst based on their respective dma_addr values, to remove the previous 32-byte alignment limitation in the EDMA memcpy function. Signed-off-by: Han Xu Reviewed-by: Frank Li Link: https://patch.msgid.link/20251119163255.502070-1-han.xu@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 45 +++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 4976d7dde080..a59212758029 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); } From 2b11e7403a8ed816fce38b57cb88e04d997aa7af Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 15 Nov 2025 13:21:22 +0100 Subject: [PATCH 23/23] dt-bindings: dma: xilinx: Simplify dma-coherent property Common boolean properties need to be only allowed in the binding (":true"), because their type is already defined by core DT schema. Simplify dma-coherent property to match common syntax. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Harini Katakam Link: https://patch.msgid.link/20251115122120.35315-5-krzk@kernel.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 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 b5399c65a731..2da86037ad79 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"