From: Jarkko Nikula <jarkko.nikula@linux.intel.com>
To: linux-i2c@vger.kernel.org
Cc: Wolfram Sang <wsa@kernel.org>,
Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
Mika Westerberg <mika.westerberg@linux.intel.com>,
Jan Dabros <jsd@semihalf.com>, Michael Wu <michael.wu@vatics.com>,
Tian Ye <tianye@sugon.com>,
Luis Oliveira <luis.oliveira@synopsys.com>,
Jarkko Nikula <jarkko.nikula@linux.intel.com>
Subject: [PATCH 01/11] i2c: designware: Fix slave state machine for sequential reads
Date: Wed, 26 Oct 2022 15:39:02 +0300 [thread overview]
Message-ID: <20221026123912.2833271-2-jarkko.nikula@linux.intel.com> (raw)
In-Reply-To: <20221026123912.2833271-1-jarkko.nikula@linux.intel.com>
Some read types from I2C bus don't work correctly when testing the
i2c-designware-slave.c with the slave-eeprom backend. The same reads
work correctly when testing with a real 24c02 EEPROM chip.
In the following tests an i2c-designware-slave.c instance with the
slave-eeprom backend is configured to act as a simulated 24c02 at
address 0x65 on an I2C host bus 6:
1. i2cdump -y 6 0x65 b (OK)
Random read. Each byte are read using a byte address write with a
current address read in a same message.
2. i2cdump -y 6 0x65 c (OK, was NOK before commit 3b5f7f10ff6e when it
was repeating the 1st byte)
Repeated current address read. One byte address write message
followed by repeated current address read messages.
3. i2cdump -y 6 0x65 i (NOK, each 32 byte block repeats the 1st byte of
block)
Sequential read using SMBus Block Read. For each 32 byte block a byte
address write followed by 32 sequental reads in a same message.
These findings are explained because the implementation has had a
mismatch between hardware interrupts and what I2C slave events should be
sent after those interrupts. Despite that the case 1 happened to have
always the I2C slave events sent to a right order with a right data
between backend and the I2C bus.
Hardware generates the DW_IC_INTR_RD_REQ interrupt when another host is
attempting to read and for sequential reads after. DW_IC_INTR_RX_DONE
occurs when host does not acknowledge a transmitted byte which is an
indication the end of transmission.
Those interrupts do not match directly with I2C_SLAVE_READ_REQUESTED and
I2C_SLAVE_READ_PROCESSED events which is how the code was and is
practically using them. The slave-eeprom backend increases the buffer
index with the I2C_SLAVE_READ_PROCESSED event and returns the data from
current index when receiving only the I2C_SLAVE_READ_REQUESTED event.
That explains the repeated bytes in case 3 and also case 2 before
commit 3b5f7f10ff6e ("i2c: designware: slave should do WRITE_REQUESTED
before WRITE_RECEIVED").
Patch fixes the case 3 while keep cases 1 and 2 working with following
changes:
- First DW_IC_INTR_RD_REQ interrupt will change the state machine to
read in progress state, send I2C_SLAVE_READ_REQUESTED event and
transmit the first byte from backend
- Subsequent DW_IC_INTR_RD_REQ interrupts will send
I2C_SLAVE_READ_PROCESSED events and transmit next bytes from backend
- STOP won't change the state machine. Otherwise case 2 won't work since
we cannot distinguish current address read from sequentiel read
- DW_IC_INTR_RX_DONE interrupt is needless since there is no mechanism
to inform it to a backend. It cannot be used to change state machine
at the end of read either due the same reason than above
- Next host write to us will change the state machine from read to write
in progress state
- STATUS_WRITE_IN_PROGRESS and STATUS_READ_IN_PROGRESS are considered
now to be status flags not the state of the driver. This is how we
treat them in i2c-designware-master.c
While at it do not test the return code from i2c_slave_event() for
I2C_SLAVE_READ_REQUESTED and I2C_SLAVE_READ_PROCESSED since it returns
always 0.
Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
drivers/i2c/busses/i2c-designware-core.h | 1 -
drivers/i2c/busses/i2c-designware-slave.c | 32 +++++++++++------------
2 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 4d3a3b464ecd..dbf6bdc5f01b 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -103,7 +103,6 @@
#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \
DW_IC_INTR_TX_EMPTY)
#define DW_IC_INTR_SLAVE_MASK (DW_IC_INTR_DEFAULT_MASK | \
- DW_IC_INTR_RX_DONE | \
DW_IC_INTR_RX_UNDER | \
DW_IC_INTR_RD_REQ)
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index 0d15f4c1e9f7..1eac4f4d5573 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -173,8 +173,9 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
enabled, slave_activity, raw_stat, stat);
if (stat & DW_IC_INTR_RX_FULL) {
- if (dev->status != STATUS_WRITE_IN_PROGRESS) {
- dev->status = STATUS_WRITE_IN_PROGRESS;
+ if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
+ dev->status |= STATUS_WRITE_IN_PROGRESS;
+ dev->status &= ~STATUS_READ_IN_PROGRESS;
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED,
&val);
}
@@ -190,24 +191,23 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
if (slave_activity) {
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
- dev->status = STATUS_READ_IN_PROGRESS;
- if (!i2c_slave_event(dev->slave,
- I2C_SLAVE_READ_REQUESTED,
- &val))
- regmap_write(dev->map, DW_IC_DATA_CMD, val);
+ if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
+ i2c_slave_event(dev->slave,
+ I2C_SLAVE_READ_REQUESTED,
+ &val);
+ dev->status |= STATUS_READ_IN_PROGRESS;
+ dev->status &= ~STATUS_WRITE_IN_PROGRESS;
+ } else {
+ i2c_slave_event(dev->slave,
+ I2C_SLAVE_READ_PROCESSED,
+ &val);
+ }
+ regmap_write(dev->map, DW_IC_DATA_CMD, val);
}
}
- if (stat & DW_IC_INTR_RX_DONE) {
- if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
- &val))
- regmap_read(dev->map, DW_IC_CLR_RX_DONE, &tmp);
- }
-
- if (stat & DW_IC_INTR_STOP_DET) {
- dev->status = STATUS_IDLE;
+ if (stat & DW_IC_INTR_STOP_DET)
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
- }
return 1;
}
--
2.35.1
next prev parent reply other threads:[~2022-10-26 12:40 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-26 12:39 [PATCH 00/11] i2c: designware: Slave fixes and generic cleanups Jarkko Nikula
2022-10-26 12:39 ` Jarkko Nikula [this message]
2022-10-26 12:39 ` [PATCH 02/11] i2c: designware: Empty receive FIFO in slave interrupt handler Jarkko Nikula
2022-10-26 12:39 ` [PATCH 03/11] i2c: designware: Define software status flags with BIT() Jarkko Nikula
2022-10-26 12:39 ` [PATCH 04/11] i2c: designware: Remove needless initializations from i2c_dw_reg_slave() Jarkko Nikula
2022-10-26 12:39 ` [PATCH 05/11] i2c: designware: Remove unused completion code from i2c-designware-slave Jarkko Nikula
2022-10-26 12:39 ` [PATCH 06/11] i2c: designware: Simplify slave interrupt handler nesting Jarkko Nikula
2022-10-26 12:39 ` [PATCH 07/11] i2c: designware: Do not process interrupt when device is suspended Jarkko Nikula
2022-10-26 13:28 ` Andy Shevchenko
2022-10-26 13:29 ` Andy Shevchenko
2022-10-26 12:39 ` [PATCH 08/11] i2c: designware: Move debug print in i2c_dw_isr() Jarkko Nikula
2022-10-26 12:39 ` [PATCH 09/11] i2c: designware: Simplify master interrupt handler nesting Jarkko Nikula
2022-10-26 12:39 ` [PATCH 10/11] i2c: designware: Remove common i2c_dw_disable_int() Jarkko Nikula
2022-10-26 13:34 ` Andy Shevchenko
2022-10-26 14:00 ` Jarkko Nikula
2022-10-26 12:39 ` [PATCH 11/11] i2c: designware: Align defines in i2c-designware-core.h Jarkko Nikula
2022-10-26 13:38 ` Andy Shevchenko
2022-11-02 13:14 ` Jarkko Nikula
2022-10-26 12:56 ` [PATCH 00/11] i2c: designware: Slave fixes and generic cleanups Andy Shevchenko
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=20221026123912.2833271-2-jarkko.nikula@linux.intel.com \
--to=jarkko.nikula@linux.intel.com \
--cc=andriy.shevchenko@linux.intel.com \
--cc=jsd@semihalf.com \
--cc=linux-i2c@vger.kernel.org \
--cc=luis.oliveira@synopsys.com \
--cc=michael.wu@vatics.com \
--cc=mika.westerberg@linux.intel.com \
--cc=tianye@sugon.com \
--cc=wsa@kernel.org \
/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.