From 8231eef24692f92ef400aa0f79ca35ff4bc0270b Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 13 Jul 2021 22:08:50 +0000 Subject: [PATCH] Ensure that we don't overrun the TX FIFO for longer transfers. Check the limit after every character, and wait for the FIFO to empty before sending out more bytes. With this I can now use ipmitool(1) to change IPMI passwords on the Ampere eMAG. ok kettenis@ --- sys/dev/ic/dwiic.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/sys/dev/ic/dwiic.c b/sys/dev/ic/dwiic.c index 84d97b8645b..b1ce2d17607 100644 --- a/sys/dev/ic/dwiic.c +++ b/sys/dev/ic/dwiic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dwiic.c,v 1.11 2020/02/20 15:33:41 cheloha Exp $ */ +/* $OpenBSD: dwiic.c,v 1.12 2021/07/13 22:08:50 patrick Exp $ */ /* * Synopsys DesignWare I2C controller * @@ -416,6 +416,42 @@ dwiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR); } + + if (I2C_OP_WRITE_P(op) && tx_limit == 0 && x < len) { + if (flags & I2C_F_POLL) { + for (retries = 1000; retries > 0; retries--) { + tx_limit = sc->tx_fifo_depth - + dwiic_read(sc, DW_IC_TXFLR); + if (tx_limit > 0) + break; + DELAY(50); + } + } else { + s = splbio(); + dwiic_read(sc, DW_IC_CLR_INTR); + dwiic_write(sc, DW_IC_INTR_MASK, + DW_IC_INTR_TX_EMPTY); + + if (tsleep_nsec(&sc->sc_writewait, PRIBIO, + "dwiic", MSEC_TO_NSEC(500)) != 0) + printf("%s: timed out waiting for " + "tx_empty intr\n", + sc->sc_dev.dv_xname); + splx(s); + + tx_limit = sc->tx_fifo_depth - + dwiic_read(sc, DW_IC_TXFLR); + } + + if (tx_limit == 0) { + printf("%s: timed out writing remaining %d\n", + sc->sc_dev.dv_xname, (int)(len - x)); + sc->sc_i2c_xfer.error = 1; + sc->sc_busy = 0; + + return (1); + } + } } if (I2C_OP_STOP_P(op) && I2C_OP_WRITE_P(op)) { -- 2.20.1