summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorJyothi Kumar Seerapu <quic_jseerapu@quicinc.com>2025-09-25 17:30:34 +0530
committerVinod Koul <vkoul@kernel.org>2025-10-16 17:47:56 +0530
commit4e8331317e73902e8b2663352c8766227e633901 (patch)
tree074023048fad2215f702c63cde93734b58563d0b /drivers/dma
parentf80ea8566917c4bb680911db839a170873e5d17c (diff)
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 <quic_jseerapu@quicinc.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/qcom/gpi.c11
1 files 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);