My iatp device works the same as before, good on boot, but fails
reading main memory map, etc on resume.

On Wed, May 23, 2018 at 11:18 PM, Mike Larkin <mlar...@azathoth.net> wrote:
> On Tue, May 22, 2018 at 05:43:01PM +0200, Mark Kettenis wrote:
>> > Date: Mon, 21 May 2018 17:25:47 -0700
>> > From: Mike Larkin <mlar...@azathoth.net>
>> >
>> > On Mon, May 21, 2018 at 12:44:47PM +0200, Mark Kettenis wrote:
>> > > The diff below fixes I2C_OP_WRITE_WITH_STOP operations.  Currently we
>> > > run the read completion code for those operations, but since there is
>> > > no data to read, this fails.  Instead, this waits until a stop is
>> > > detected.  That doesn't seem to work for I2C_F_POLL operations though,
>> > > so in that case we wait until the bus is idle.  This also adds
>> > > interlocks (using splbio/splx) on the existing tsleep() operations.
>> > >
>> > > This doesn't fix all the issues with the driver.  In particular it
>> > > seems that large reads still cause problems.  I think a somewhat more
>> > > invasive re-write of the dwiic_i2c_exec() function is needed.  But I'd
>> > > like to get this in before I embark on that.
>> > >
>> > > ok?
>> > >
>> >
>> > The diff reads ok to me, do you want us to do any sort of testing here 
>> > before
>> > commit?
>>
>> Testing is always appreciated, and a goood idea if you own a machine
>> that relies on dwiic(4).  For example those with machines that have a
>> keyboard or touchpad/screen connected over i2c.
>>
>> Cheers,
>>
>> Mark
>>
>
> No regressions seen here.
>
> -ml
>
>> > > Index: dev/ic/dwiic.c
>> > > ===================================================================
>> > > RCS file: /cvs/src/sys/dev/ic/dwiic.c,v
>> > > retrieving revision 1.3
>> > > diff -u -p -r1.3 dwiic.c
>> > > --- dev/ic/dwiic.c        19 Jan 2018 18:20:38 -0000      1.3
>> > > +++ dev/ic/dwiic.c        21 May 2018 10:37:50 -0000
>> > > @@ -192,6 +192,7 @@ dwiic_i2c_exec(void *cookie, i2c_op_t op
>> > >   u_int32_t ic_con, st, cmd, resp;
>> > >   int retries, tx_limit, rx_avail, x, readpos;
>> > >   uint8_t *b;
>> > > + int s;
>> > >
>> > >   if (sc->sc_busy)
>> > >           return 1;
>> > > @@ -245,12 +246,14 @@ dwiic_i2c_exec(void *cookie, i2c_op_t op
>> > >   if (flags & I2C_F_POLL)
>> > >           DELAY(200);
>> > >   else {
>> > > +         s = splbio();
>> > >           dwiic_read(sc, DW_IC_CLR_INTR);
>> > >           dwiic_write(sc, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY);
>> > >
>> > >           if (tsleep(&sc->sc_writewait, PRIBIO, "dwiic", hz / 2) != 0)
>> > >                   printf("%s: timed out waiting for tx_empty intr\n",
>> > >                       sc->sc_dev.dv_xname);
>> > > +         splx(s);
>> > >   }
>> > >
>> > >   /* send our command, one byte at a time */
>> > > @@ -320,7 +323,7 @@ dwiic_i2c_exec(void *cookie, i2c_op_t op
>> > >            * As TXFLR fills up, we need to clear it out by reading all
>> > >            * available data.
>> > >            */
>> > > -         while (tx_limit == 0 || x == len) {
>> > > +         while (I2C_OP_READ_P(op) && (tx_limit == 0 || x == len)) {
>> > >                   DPRINTF(("%s: %s: tx_limit %d, sent %d read reqs\n",
>> > >                       sc->sc_dev.dv_xname, __func__, tx_limit, x));
>> > >
>> > > @@ -332,6 +335,7 @@ dwiic_i2c_exec(void *cookie, i2c_op_t op
>> > >                                   DELAY(50);
>> > >                           }
>> > >                   } else {
>> > > +                         s = splbio();
>> > >                           dwiic_read(sc, DW_IC_CLR_INTR);
>> > >                           dwiic_write(sc, DW_IC_INTR_MASK,
>> > >                               DW_IC_INTR_RX_FULL);
>> > > @@ -341,6 +345,7 @@ dwiic_i2c_exec(void *cookie, i2c_op_t op
>> > >                                   printf("%s: timed out waiting for "
>> > >                                       "rx_full intr\n",
>> > >                                       sc->sc_dev.dv_xname);
>> > > +                         splx(s);
>> > >
>> > >                           rx_avail = dwiic_read(sc, DW_IC_RXFLR);
>> > >                   }
>> > > @@ -378,6 +383,32 @@ dwiic_i2c_exec(void *cookie, i2c_op_t op
>> > >           }
>> > >   }
>> > >
>> > > + if (I2C_OP_STOP_P(op) && I2C_OP_WRITE_P(op)) {
>> > > +         if (flags & I2C_F_POLL) {
>> > > +                 /* wait for bus to be idle */
>> > > +                 for (retries = 100; retries > 0; retries--) {
>> > > +                         st = dwiic_read(sc, DW_IC_STATUS);
>> > > +                         if (!(st & DW_IC_STATUS_ACTIVITY))
>> > > +                                 break;
>> > > +                         DELAY(1000);
>> > > +                 }
>> > > +                 if (st & DW_IC_STATUS_ACTIVITY)
>> > > +                         printf("%s: timed out waiting for bus idle\n",
>> > > +                             sc->sc_dev.dv_xname);
>> > > +         } else {
>> > > +                 s = splbio();
>> > > +                 while (sc->sc_busy) {
>> > > +                         dwiic_write(sc, DW_IC_INTR_MASK,
>> > > +                             DW_IC_INTR_STOP_DET);
>> > > +                         if (tsleep(&sc->sc_busy, PRIBIO, "dwiic",
>> > > +                             hz / 2) != 0)
>> > > +                                 printf("%s: timed out waiting for "
>> > > +                                     "stop intr\n",
>> > > +                                     sc->sc_dev.dv_xname);
>> > > +                 }
>> > > +                 splx(s);
>> > > +         }
>> > > + }
>> > >   sc->sc_busy = 0;
>> > >
>> > >   return 0;
>> > > @@ -449,6 +480,11 @@ dwiic_intr(void *arg)
>> > >                   DPRINTF(("%s: %s: waking up writer\n",
>> > >                       sc->sc_dev.dv_xname, __func__));
>> > >                   wakeup(&sc->sc_writewait);
>> > > +         }
>> > > +         if (stat & DW_IC_INTR_STOP_DET) {
>> > > +                 dwiic_write(sc, DW_IC_INTR_MASK, 0);
>> > > +                 sc->sc_busy = 0;
>> > > +                 wakeup(&sc->sc_busy);
>> > >           }
>> > >   }
>> > >
>> > >
>> >
>

Reply via email to