mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
i2c: designware: queue only one read command for block reads
i2c_dw_xfer_msg() pre-queues up to rx_fifo_depth read commands based
on the initial msg.len. For I2C_M_RECV_LEN transfers the real length
is unknown until the first byte arrives and i2c_dw_recv_len() runs.
When a large initial length is passed, the surplus pre-queued reads
leave rx_outstanding non-zero after i2c_dw_recv_len() adjusts
msg.len, so the completion condition is never met and the transfer
times out. In a loop, this repeatedly times out the controller and
disrupts unrelated driver-bound devices on the same adapter.
Queue only one read command while I2C_M_RECV_LEN is pending.
i2c_dw_recv_len() re-enables TX_EMPTY, and the rest are queued once
the device-reported length is known.
Fixes: c3ae106050 ("i2c: designware: Implement support for SMBus block read and write")
Signed-off-by: Navon John Lukose <navonjohnlukose@gmail.com>
Cc: <stable@vger.kernel.org> # v4.10+
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
This commit is contained in:
parent
a65917d0a2
commit
73dae605ca
|
|
@ -441,6 +441,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|||
if (dev->rx_outstanding >= dev->rx_fifo_depth)
|
||||
break;
|
||||
|
||||
/*
|
||||
* For block reads, queue only the length
|
||||
* byte until i2c_dw_recv_len() runs.
|
||||
*/
|
||||
if ((flags & I2C_M_RECV_LEN) &&
|
||||
buf_len < msgs[dev->msg_write_idx].len)
|
||||
break;
|
||||
|
||||
regmap_write(dev->map, DW_IC_DATA_CMD,
|
||||
cmd | 0x100);
|
||||
rx_limit--;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user