* [PATCH V3] i2c: qcom-geni: Avoid extra TX DMA TRE for single read message in GPI mode
@ 2026-04-03 8:41 Aniket Randive
2026-04-06 4:38 ` Mukesh Savaliya
0 siblings, 1 reply; 3+ messages in thread
From: Aniket Randive @ 2026-04-03 8:41 UTC (permalink / raw)
To: mukesh.savaliya, viken.dadhaniya, andi.shyti, sumit.semwal,
christian.koenig
Cc: linux-i2c, linux-arm-msm, linux-kernel, linux-media, dri-devel,
linaro-mm-sig, naresh.maramaina, aniket.randive
In GPI mode, the I2C GENI driver programs an extra TX DMA transfer
descriptor (TRE) on the TX channel when handling a single read message.
This results in an unintended write phase being issued on the I2C bus,
even though a read transaction does not require any TX data.
For a single-byte read, the correct hardware sequence consists of the
CONFIG and GO commands followed by a single RX DMA TRE. Programming an
additional TX DMA TRE is redundant, causes unnecessary DMA buffer
mapping on the TX channel, and may lead to incorrect bus behavior.
Update the transfer logic to avoid programming a TX DMA TRE for single
read messages in GPI mode.
Co-developed-by: Maramaina Naresh <naresh.maramaina@oss.qualcomm.com>
Signed-off-by: Maramaina Naresh <naresh.maramaina@oss.qualcomm.com>
Signed-off-by: Aniket Randive <aniket.randive@oss.qualcomm.com>
---
Changes in v3:
- Added comment in the driver for better readability and changed the
position of 'skip_dma' label to allow dma engine configuration.
Changes in v2:
- Updated the commit message.
drivers/i2c/busses/i2c-qcom-geni.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index a4acb78fafb6..78b92db7c7fd 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -625,8 +625,8 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
{
struct gpi_i2c_config *peripheral;
unsigned int flags;
- void *dma_buf;
- dma_addr_t addr;
+ void *dma_buf = NULL;
+ dma_addr_t addr = 0;
enum dma_data_direction map_dirn;
enum dma_transfer_direction dma_dirn;
struct dma_async_tx_descriptor *desc;
@@ -639,6 +639,12 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
gi2c_gpi_xfer = &gi2c->i2c_multi_desc_config;
msg_idx = gi2c_gpi_xfer->msg_idx_cnt;
+ /* Skip TX DMA map for I2C_WRITE operation to avoid unintended write cycle */
+ if (op == I2C_WRITE && msgs[msg_idx].flags & I2C_M_RD) {
+ peripheral->multi_msg = true;
+ goto skip_dma;
+ }
+
dma_buf = i2c_get_dma_safe_msg_buf(&msgs[msg_idx], 1);
if (!dma_buf) {
ret = -ENOMEM;
@@ -658,6 +664,7 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
goto out;
}
+skip_dma:
if (gi2c->is_tx_multi_desc_xfer) {
flags = DMA_CTRL_ACK;
@@ -740,9 +747,12 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
return 0;
err_config:
- 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);
+ /* Avoid DMA unmap as the write operation skipped DMA mapping */
+ if (dma_buf) {
+ 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;
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH V3] i2c: qcom-geni: Avoid extra TX DMA TRE for single read message in GPI mode
2026-04-03 8:41 [PATCH V3] i2c: qcom-geni: Avoid extra TX DMA TRE for single read message in GPI mode Aniket Randive
@ 2026-04-06 4:38 ` Mukesh Savaliya
2026-04-10 10:16 ` Aniket RANDIVE
0 siblings, 1 reply; 3+ messages in thread
From: Mukesh Savaliya @ 2026-04-06 4:38 UTC (permalink / raw)
To: Aniket Randive, viken.dadhaniya, andi.shyti, sumit.semwal,
christian.koenig
Cc: linux-i2c, linux-arm-msm, linux-kernel, linux-media, dri-devel,
linaro-mm-sig, naresh.maramaina
On 4/3/2026 2:11 PM, Aniket Randive wrote:
> In GPI mode, the I2C GENI driver programs an extra TX DMA transfer
> descriptor (TRE) on the TX channel when handling a single read message.
> This results in an unintended write phase being issued on the I2C bus,
> even though a read transaction does not require any TX data.
>
> For a single-byte read, the correct hardware sequence consists of the
> CONFIG and GO commands followed by a single RX DMA TRE. Programming an
> additional TX DMA TRE is redundant, causes unnecessary DMA buffer
> mapping on the TX channel, and may lead to incorrect bus behavior.
>
> Update the transfer logic to avoid programming a TX DMA TRE for single
> read messages in GPI mode.
>
> Co-developed-by: Maramaina Naresh <naresh.maramaina@oss.qualcomm.com>
> Signed-off-by: Maramaina Naresh <naresh.maramaina@oss.qualcomm.com>
> Signed-off-by: Aniket Randive <aniket.randive@oss.qualcomm.com>
> ---
> Changes in v3:
> - Added comment in the driver for better readability and changed the
> position of 'skip_dma' label to allow dma engine configuration.
>
> Changes in v2:
> - Updated the commit message.
>
> drivers/i2c/busses/i2c-qcom-geni.c | 20 +++++++++++++++-----
> 1 file changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
> index a4acb78fafb6..78b92db7c7fd 100644
> --- a/drivers/i2c/busses/i2c-qcom-geni.c
> +++ b/drivers/i2c/busses/i2c-qcom-geni.c
> @@ -625,8 +625,8 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
> {
> struct gpi_i2c_config *peripheral;
> unsigned int flags;
> - void *dma_buf;
> - dma_addr_t addr;
> + void *dma_buf = NULL;
> + dma_addr_t addr = 0;
> enum dma_data_direction map_dirn;
> enum dma_transfer_direction dma_dirn;
> struct dma_async_tx_descriptor *desc;
> @@ -639,6 +639,12 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
> gi2c_gpi_xfer = &gi2c->i2c_multi_desc_config;
> msg_idx = gi2c_gpi_xfer->msg_idx_cnt;
>
> + /* Skip TX DMA map for I2C_WRITE operation to avoid unintended write cycle */
Seems you are missing writing important point - For read message ?
Important is to clarity what's the condition we are handling, Skipping
something is anyway clear from goto skip_dma.
> + if (op == I2C_WRITE && msgs[msg_idx].flags & I2C_M_RD) {
> + peripheral->multi_msg = true;
> + goto skip_dma;
> + }
> +
> dma_buf = i2c_get_dma_safe_msg_buf(&msgs[msg_idx], 1);
> if (!dma_buf) {
> ret = -ENOMEM;
> @@ -658,6 +664,7 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
> goto out;
> }
>
> +skip_dma:
Better name - skip_tx_dma_map ?
> if (gi2c->is_tx_multi_desc_xfer) {
> flags = DMA_CTRL_ACK;
>
> @@ -740,9 +747,12 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
> return 0;
>
> err_config:
> - 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);
> + /* Avoid DMA unmap as the write operation skipped DMA mapping */
> + if (dma_buf) {
> + 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;
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH V3] i2c: qcom-geni: Avoid extra TX DMA TRE for single read message in GPI mode
2026-04-06 4:38 ` Mukesh Savaliya
@ 2026-04-10 10:16 ` Aniket RANDIVE
0 siblings, 0 replies; 3+ messages in thread
From: Aniket RANDIVE @ 2026-04-10 10:16 UTC (permalink / raw)
To: Mukesh Savaliya, viken.dadhaniya, andi.shyti, sumit.semwal,
christian.koenig
Cc: linux-i2c, linux-arm-msm, linux-kernel, linux-media, dri-devel,
linaro-mm-sig, naresh.maramaina
On 4/6/2026 10:08 AM, Mukesh Savaliya wrote:
>
>
> On 4/3/2026 2:11 PM, Aniket Randive wrote:
>> In GPI mode, the I2C GENI driver programs an extra TX DMA transfer
>> descriptor (TRE) on the TX channel when handling a single read message.
>> This results in an unintended write phase being issued on the I2C bus,
>> even though a read transaction does not require any TX data.
>>
>> For a single-byte read, the correct hardware sequence consists of the
>> CONFIG and GO commands followed by a single RX DMA TRE. Programming an
>> additional TX DMA TRE is redundant, causes unnecessary DMA buffer
>> mapping on the TX channel, and may lead to incorrect bus behavior.
>>
>> Update the transfer logic to avoid programming a TX DMA TRE for single
>> read messages in GPI mode.
>>
>> Co-developed-by: Maramaina Naresh <naresh.maramaina@oss.qualcomm.com>
>> Signed-off-by: Maramaina Naresh <naresh.maramaina@oss.qualcomm.com>
>> Signed-off-by: Aniket Randive <aniket.randive@oss.qualcomm.com>
>> ---
>> Changes in v3:
>> - Added comment in the driver for better readability and changed the
>> position of 'skip_dma' label to allow dma engine configuration.
>>
>> Changes in v2:
>> - Updated the commit message.
>>
>> drivers/i2c/busses/i2c-qcom-geni.c | 20 +++++++++++++++-----
>> 1 file changed, 15 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/
>> i2c-qcom-geni.c
>> index a4acb78fafb6..78b92db7c7fd 100644
>> --- a/drivers/i2c/busses/i2c-qcom-geni.c
>> +++ b/drivers/i2c/busses/i2c-qcom-geni.c
>> @@ -625,8 +625,8 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c,
>> struct i2c_msg msgs[],
>> {
>> struct gpi_i2c_config *peripheral;
>> unsigned int flags;
>> - void *dma_buf;
>> - dma_addr_t addr;
>> + void *dma_buf = NULL;
>> + dma_addr_t addr = 0;
>> enum dma_data_direction map_dirn;
>> enum dma_transfer_direction dma_dirn;
>> struct dma_async_tx_descriptor *desc;
>> @@ -639,6 +639,12 @@ static int geni_i2c_gpi(struct geni_i2c_dev
>> *gi2c, struct i2c_msg msgs[],
>> gi2c_gpi_xfer = &gi2c->i2c_multi_desc_config;
>> msg_idx = gi2c_gpi_xfer->msg_idx_cnt;
>> + /* Skip TX DMA map for I2C_WRITE operation to avoid unintended
>> write cycle */
> Seems you are missing writing important point - For read message ?
> Important is to clarity what's the condition we are handling, Skipping
> something is anyway clear from goto skip_dma.
Sure, will add more description in comment for better understanding.
-Aniket
>> + if (op == I2C_WRITE && msgs[msg_idx].flags & I2C_M_RD) {
>> + peripheral->multi_msg = true;
>> + goto skip_dma;
>> + }
>> +
>> dma_buf = i2c_get_dma_safe_msg_buf(&msgs[msg_idx], 1);
>> if (!dma_buf) {
>> ret = -ENOMEM;
>> @@ -658,6 +664,7 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c,
>> struct i2c_msg msgs[],
>> goto out;
>> }
>> +skip_dma:
> Better name - skip_tx_dma_map ?
Sure. I will change it.
-Aniket
>> if (gi2c->is_tx_multi_desc_xfer) {
>> flags = DMA_CTRL_ACK;
>> @@ -740,9 +747,12 @@ static int geni_i2c_gpi(struct geni_i2c_dev
>> *gi2c, struct i2c_msg msgs[],
>> return 0;
>> err_config:
>> - 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);
>> + /* Avoid DMA unmap as the write operation skipped DMA mapping */
>> + if (dma_buf) {
>> + 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;
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-04-10 10:16 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-03 8:41 [PATCH V3] i2c: qcom-geni: Avoid extra TX DMA TRE for single read message in GPI mode Aniket Randive
2026-04-06 4:38 ` Mukesh Savaliya
2026-04-10 10:16 ` Aniket RANDIVE
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox