* [PATCH] i2c: xiic: Rework dynamic-mode RX FIFO drain in xiic_read_rx
@ 2026-09-01 7:08 Vasantha Likitha T
0 siblings, 0 replies; only message in thread
From: Vasantha Likitha T @ 2026-09-01 7:08 UTC (permalink / raw)
To: linux-i2c
Cc: michal.simek, andi.shyti, linux-kernel, git, Shubhrajyoti Datta,
Vasantha Likitha T
From: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Programming the RFD (RX FIFO depth) threshold at runtime causes a
spurious SCL clock pulse which results in the STOP condition being
missed.
Fix this by programming RFD once, when the receive transfer starts, and
handling the final-byte sequencing in software: select how many bytes to
drain from the RX FIFO on each RX_FULL interrupt instead of
reprogramming RFD after every read.
RX_FULL is then always raised at the same threshold. When fewer bytes
remain outstanding than the FIFO holds, drain only those and leave the
rest behind, so the retained bytes plus those still to arrive restore
occupancy to the threshold; otherwise drain the FIFO completely. This
relies on RFO accounting for every byte received, or the threshold is
never reached again and the transfer stalls until the xiic_xfer()
timeout.
Fixes: acea4e4458b4 ("i2c: xiic: Add standard mode support for > 255 byte")
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Co-developed-by: Vasantha Likitha T <vasanthalikitha.tandra@amd.com>
Signed-off-by: Vasantha Likitha T <vasanthalikitha.tandra@amd.com>
---
drivers/i2c/busses/i2c-xiic.c | 53 +++++++++++++++++++++++++++--------
1 file changed, 41 insertions(+), 12 deletions(-)
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 28015d77599d..81b163152953 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -580,6 +580,7 @@ static void xiic_read_rx(struct xiic_i2c *i2c)
{
u8 bytes_in_fifo, cr = 0, bytes_to_read = 0;
u32 bytes_rem = 0;
+ u32 rx_space;
int i;
bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1;
@@ -591,12 +592,49 @@ static void xiic_read_rx(struct xiic_i2c *i2c)
xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
- if (bytes_in_fifo > xiic_rx_space(i2c))
- bytes_in_fifo = xiic_rx_space(i2c);
+ rx_space = xiic_rx_space(i2c);
+
+ /* Do not read more bytes than are still expected for this message */
+ if (bytes_in_fifo > rx_space)
+ bytes_in_fifo = rx_space;
bytes_to_read = bytes_in_fifo;
- if (!i2c->dynamic) {
+ if (i2c->dynamic) {
+ /*
+ * RFD is programmed by xiic_start_recv() and left untouched
+ * here: reprogramming it mid-transfer emits a spurious SCL
+ * pulse, causing the STOP condition to be missed.
+ *
+ * RX_FULL is therefore always raised at the same threshold.
+ * When fewer bytes remain outstanding than are held in the
+ * FIFO, drain only those; the retained bytes plus the final
+ * incoming bytes restore occupancy to the threshold and raise
+ * RX_FULL once more. This relies on RFO accounting for every
+ * byte the controller has received; otherwise the threshold is
+ * never reached again and the transfer stalls until the
+ * xiic_xfer() timeout.
+ */
+ bytes_rem = rx_space - bytes_in_fifo;
+
+ if (!bytes_rem) {
+ /* Every remaining byte is already in the FIFO */
+ bytes_to_read = bytes_in_fifo;
+ } else if (bytes_rem < bytes_in_fifo) {
+ /*
+ * Drain only the outstanding bytes and leave the
+ * rest behind, so that they and the bytes still to
+ * arrive restore occupancy to the threshold.
+ */
+ bytes_to_read = bytes_rem;
+ } else {
+ /*
+ * At least as many bytes outstanding as are in the
+ * FIFO, so it can be drained completely.
+ */
+ bytes_to_read = bytes_in_fifo;
+ }
+ } else {
bytes_rem = xiic_rx_space(i2c) - bytes_in_fifo;
/* Set msg length if smbus_block_read */
@@ -637,15 +675,6 @@ static void xiic_read_rx(struct xiic_i2c *i2c)
i2c->rx_msg->buf[i2c->rx_pos++] =
xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
}
-
- if (i2c->dynamic) {
- u8 bytes;
-
- /* Receive remaining bytes if less than fifo depth */
- bytes = min_t(u8, xiic_rx_space(i2c), IIC_RX_FIFO_DEPTH);
- bytes--;
- xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, bytes);
- }
}
static bool xiic_error_check(struct xiic_i2c *i2c)
--
2.43.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-01 7:08 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 7:08 [PATCH] i2c: xiic: Rework dynamic-mode RX FIFO drain in xiic_read_rx Vasantha Likitha T
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).