Am Mon, Jul 05, 2021 at 06:34:31PM +0200 schrieb Mark Kettenis:
> > Date: Mon, 5 Jul 2021 00:04:24 +0200
> > From: Patrick Wildt <[email protected]>
> >
> > Hi,
> >
> > I had trouble interfacing with a machine's IPMI through dwiic(4). What
> > I saw was that when sending 'bigger' commands, it would never receive
> > the STOP bit interrupt.
> >
> > The trouble is, as can be seen in the log, that we want to send (it
> > says read, but it's a write OP, so it's send) 20 bytes, but the tx
> > limit says 14.
> >
> > What we should do is send 14 bytes, then wait for it to send us the
> > tx empty interrupt (like we do when we first enable the controller),
> > and then re-read the tx limit. The last line in the log is some
> > debug print I added for myself, but is not part of the diff.
> >
> > With this, I was finally able to change the IPMI password and regain
> > access to the web interface after updating the BMC's firmware...
> >
> > dwiic0: dwiic_i2c_exec: op 7, addr 0x10, cmdlen 2, len 3, flags 0x00
> > dwiic0: dwiic_i2c_exec: need to read 3 bytes, can send 14 read reqs
> > dwiic0: dwiic_i2c_exec: op 5, addr 0x10, cmdlen 1, len 33, flags 0x00
> > dwiic0: dwiic_i2c_exec: need to read 33 bytes, can send 15 read reqs
> > dwiic0: dwiic_i2c_exec: op 7, addr 0x10, cmdlen 2, len 20, flags 0x00
> > dwiic0: dwiic_i2c_exec: need to read 20 bytes, can send 14 read reqs
> > dwiic0: new tx limit 8
> >
> > Opinions? ok?
>
> I think you're on to something. But this needs to handle I2C_F_POLL.
True that. The previous code, which waits for the controller to accept
commands, just does DELAY(200), but I'm not sure that's good enough for
inbetween transfers. One can apparently though poll through the raw
interrupt status register, where the interrupt mask isn't applied. So
maybe like that? Guess I should try setting ipmi to polling mode...
> > diff --git a/sys/dev/ic/dwiic.c b/sys/dev/ic/dwiic.c
> > index 84d97b8645b..d04a7b03979 100644
> > --- a/sys/dev/ic/dwiic.c
> > +++ b/sys/dev/ic/dwiic.c
> > @@ -416,6 +416,21 @@ 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) {
> > + 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 (I2C_OP_STOP_P(op) && I2C_OP_WRITE_P(op)) {
> >
> >
>