aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2021-11-26 08:34:42 +0000
committerAndriy Gapon <avg@FreeBSD.org>2021-11-26 14:18:51 +0000
commit00c07d9559c6197957b00811a0b29876a5c8b573 (patch)
tree9ab859ffa97e90e742dd32558d6d2ec0db0fdba0
parentaeacf172fd29b16b3661ff057c9abb238baba813 (diff)
downloadsrc-00c07d9559c6197957b00811a0b29876a5c8b573.tar.gz
src-00c07d9559c6197957b00811a0b29876a5c8b573.zip
twsi: make data receiving code safer
Assert that we are not receiving data beyond the requested length. Assert that we have not NACK-ed incoming data prematurely. Abort the current transfer if the incoming data is NACK-ed or not NACK-ed unexpectedly. Add debug logging of received data to complement logging of sent data. MFC after: 3 weeks
-rw-r--r--sys/dev/iicbus/twsi/twsi.c62
1 files changed, 41 insertions, 21 deletions
diff --git a/sys/dev/iicbus/twsi/twsi.c b/sys/dev/iicbus/twsi/twsi.c
index b94396883be5..2f77e2dc69c3 100644
--- a/sys/dev/iicbus/twsi/twsi.c
+++ b/sys/dev/iicbus/twsi/twsi.c
@@ -671,37 +671,57 @@ twsi_intr(void *arg)
break;
case TWSI_STATUS_DATA_RD_ACK:
- debugf(sc, "Ack received after receiving data\n");
- sc->msgs[sc->msg_idx].buf[sc->recv_bytes++] = TWSI_READ(sc, sc->reg_data);
- debugf(sc, "msg_len=%d recv_bytes=%d\n", sc->msgs[sc->msg_idx].len, sc->recv_bytes);
+ debugf(sc, "Received and ACK-ed data\n");
+ KASSERT(sc->recv_bytes < sc->msgs[sc->msg_idx].len,
+ ("receiving beyond the end of buffer"));
+
+ sc->msgs[sc->msg_idx].buf[sc->recv_bytes] =
+ TWSI_READ(sc, sc->reg_data);
+ debugf(sc, "Received byte %d (of %d) = 0x%x\n",
+ sc->recv_bytes,
+ sc->msgs[sc->msg_idx].len,
+ sc->msgs[sc->msg_idx].buf[sc->recv_bytes]);
+ sc->recv_bytes++;
/* If we only have one byte left, disable ACK */
- if (sc->msgs[sc->msg_idx].len - sc->recv_bytes == 1)
+ if (sc->msgs[sc->msg_idx].len - sc->recv_bytes == 1) {
sc->control_val &= ~TWSI_CONTROL_ACK;
- if (sc->msgs[sc->msg_idx].len == sc->recv_bytes) {
- debugf(sc, "Done with msg %d\n", sc->msg_idx);
- sc->msg_idx++;
- if (sc->msg_idx == sc->nmsgs - 1) {
- debugf(sc, "No more msgs\n");
- transfer_done = 1;
- sc->error = 0;
- }
+ } else if (sc->msgs[sc->msg_idx].len == sc->recv_bytes) {
+ /*
+ * We should not have ACK-ed the last byte.
+ * The protocol state machine is in invalid state.
+ */
+ debugf(sc, "RX all but asked for more?\n");
+ twsi_error(sc, IIC_ESTATUS);
}
- TWSI_WRITE(sc, sc->reg_control, sc->control_val);
break;
case TWSI_STATUS_DATA_RD_NOACK:
- if (sc->msgs[sc->msg_idx].len - sc->recv_bytes == 1) {
- sc->msgs[sc->msg_idx].buf[sc->recv_bytes++] = TWSI_READ(sc, sc->reg_data);
- debugf(sc, "Done RX data, send stop (2)\n");
- if (!(sc->msgs[sc->msg_idx].flags & IIC_M_NOSTOP))
+ debugf(sc, "Received and NACK-ed data\n");
+ KASSERT(sc->recv_bytes == sc->msgs[sc->msg_idx].len - 1,
+ ("sent NACK before receiving all requested data"));
+ sc->msgs[sc->msg_idx].buf[sc->recv_bytes] =
+ TWSI_READ(sc, sc->reg_data);
+ debugf(sc, "Received byte %d (of %d) = 0x%x\n",
+ sc->recv_bytes,
+ sc->msgs[sc->msg_idx].len,
+ sc->msgs[sc->msg_idx].buf[sc->recv_bytes]);
+ sc->recv_bytes++;
+
+ if (sc->msgs[sc->msg_idx].len == sc->recv_bytes) {
+ debugf(sc, "Done RX data\n");
+ if (!(sc->msgs[sc->msg_idx].flags & IIC_M_NOSTOP)) {
+ debugf(sc, "Send STOP\n");
TWSI_WRITE(sc, sc->reg_control,
sc->control_val | TWSI_CONTROL_STOP);
+ }
} else {
- debugf(sc, "No ack when receiving data, sending stop anyway\n");
- if (!(sc->msgs[sc->msg_idx].flags & IIC_M_NOSTOP))
- TWSI_WRITE(sc, sc->reg_control,
- sc->control_val | TWSI_CONTROL_STOP);
+ /*
+ * We should not have NACK-ed yet.
+ * The protocol state machine is in invalid state.
+ */
+ debugf(sc, "NACK-ed before receving all bytes?\n");
+ twsi_error(sc, IIC_ESTATUS);
}
sc->transfer = 0;
transfer_done = 1;