All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jarkko Nikula <jarkko.nikula@linux.intel.com>
To: David Zheng <david.zheng@intel.com>,
	linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: andriy.shevchenko@linux.intel.com,
	mika.westerberg@linux.intel.com, jsd@semihalf.com
Subject: Re: [PATCH v3] i2c: designware: fix idx_write_cnt in read loop
Date: Fri, 26 May 2023 16:58:26 +0300	[thread overview]
Message-ID: <f9a38ff8-ca08-a9aa-e2ff-ce2ce956235a@linux.intel.com> (raw)
In-Reply-To: <ZG5UI7cJvmLXvtLg@davidzhe-DESK>

On 5/24/23 21:14, David Zheng wrote:
> With IC_INTR_RX_FULL slave interrupt handler reads data in a loop until
> RX FIFO is empty. When testing with the slave-eeprom, each transaction
> has 2 bytes for address/index and 1 byte for value, the address byte
> can be written as data byte due to dropping STOP condition.
> 
> In the test below, the master continuously writes to the slave, first 2
> bytes are index, 3rd byte is value and follow by a STOP condition.
> 
>   i2c_write: i2c-3 #0 a=04b f=0000 l=3 [00-D1-D1]
>   i2c_write: i2c-3 #0 a=04b f=0000 l=3 [00-D2-D2]
>   i2c_write: i2c-3 #0 a=04b f=0000 l=3 [00-D3-D3]
> 
> Upon receiving STOP condition slave eeprom would reset `idx_write_cnt` so
> next 2 bytes can be treated as buffer index for upcoming transaction.
> Supposedly the slave eeprom buffer would be written as
> 
>   EEPROM[0x00D1] = 0xD1
>   EEPROM[0x00D2] = 0xD2
>   EEPROM[0x00D3] = 0xD3
> 
> When CPU load is high the slave irq handler may not read fast enough,
> the interrupt status can be seen as 0x204 with both DW_IC_INTR_STOP_DET
> (0x200) and DW_IC_INTR_RX_FULL (0x4) bits. The slave device may see
> the transactions below.
> 
>   0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x1594 : INTR_STAT=0x4
>   0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x1594 : INTR_STAT=0x4
>   0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x1594 : INTR_STAT=0x4
>   0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x1794 : INTR_STAT=0x204
>   0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x1790 : INTR_STAT=0x200
>   0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x1594 : INTR_STAT=0x4
>   0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x1594 : INTR_STAT=0x4
>   0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x1594 : INTR_STAT=0x4
> 
> After `D1` is received, read loop continues to read `00` which is the
> first bype of next index. Since STOP condition is ignored by the loop,
> eeprom buffer index increased to `D2` and `00` is written as value.
> 
> So the slave eeprom buffer becomes
> 
>   EEPROM[0x00D1] = 0xD1
>   EEPROM[0x00D2] = 0x00
>   EEPROM[0x00D3] = 0xD3
> 
> The fix is to use `FIRST_DATA_BYTE` (bit 11) in `IC_DATA_CMD` to split
> the transactions. The first index byte in this case would have bit 11
> set. Check this indication to inject I2C_SLAVE_WRITE_REQUESTED event
> which will reset `idx_write_cnt` in slave eeprom.
> 
> Signed-off-by: David Zheng <david.zheng@intel.com>
> ---
> Changes in v2:
>   - Send I2C_SLAVE_WRITE_REQUESTED for HW does not have FIRST_DATA_BYTE
> Changes in v3:
>   - Move DW_IC_DATA_CMD_FIRST_DATA_BYTE next to DW_IC_DATA_CMD_DAT define
> ---
>   drivers/i2c/busses/i2c-designware-core.h  | 1 +
>   drivers/i2c/busses/i2c-designware-slave.c | 4 ++++
>   2 files changed, 5 insertions(+)
> 
> diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
> index c5d87aae39c6..bf23bfb51aea 100644
> --- a/drivers/i2c/busses/i2c-designware-core.h
> +++ b/drivers/i2c/busses/i2c-designware-core.h
> @@ -40,6 +40,7 @@
>   #define DW_IC_CON_BUS_CLEAR_CTRL		BIT(11)
>   
>   #define DW_IC_DATA_CMD_DAT			GENMASK(7, 0)
> +#define DW_IC_DATA_CMD_FIRST_DATA_BYTE		BIT(11)
>   
>   /*
>    * Registers offset
> diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
> index cec25054bb24..2e079cf20bb5 100644
> --- a/drivers/i2c/busses/i2c-designware-slave.c
> +++ b/drivers/i2c/busses/i2c-designware-slave.c
> @@ -176,6 +176,10 @@ static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
>   
>   		do {
>   			regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
> +			if (tmp & DW_IC_DATA_CMD_FIRST_DATA_BYTE)
> +				i2c_slave_event(dev->slave,
> +						I2C_SLAVE_WRITE_REQUESTED,
> +						&val);
>   			val = tmp;
>   			i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
>   					&val);

Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>

  reply	other threads:[~2023-05-26 13:58 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-24 18:14 [PATCH v3] i2c: designware: fix idx_write_cnt in read loop David Zheng
2023-05-26 13:58 ` Jarkko Nikula [this message]
2023-06-05 10:02   ` Wolfram Sang
2023-06-05 10:48     ` Jarkko Nikula
2023-06-05 12:36       ` Wolfram Sang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f9a38ff8-ca08-a9aa-e2ff-ce2ce956235a@linux.intel.com \
    --to=jarkko.nikula@linux.intel.com \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=david.zheng@intel.com \
    --cc=jsd@semihalf.com \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mika.westerberg@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.