Re: Another dwiic(4) fix

2019-08-17 Thread Mike Larkin
On Sat, Aug 17, 2019 at 06:42:01PM +0200, Mark Kettenis wrote:
> The timeout when waiting for data to be received for polled mode is
> too small for taling to the BMC on the Ampere/Lenovo arm64 server.
> This bumps it to 50 ms, which is still lower than what it is for
> non-polled mode.
> 
> I also found that things worked much better if we checked for the
> actually STOP detection bit to come instead of looking at the activity
> bit in the status register.
> 
> Also tested on my Asus x205ta, which has an i2c keyboard.
> 
> ok?
> 
> 

This causes no regressions on the 2 machines I tried.

Probably the right time to get it in, ok mlarkin

> Index: dwiic.c
> ===
> RCS file: /cvs/src/sys/dev/ic/dwiic.c,v
> retrieving revision 1.6
> diff -u -p -r1.6 dwiic.c
> --- dwiic.c   6 Aug 2019 06:56:29 -   1.6
> +++ dwiic.c   17 Aug 2019 16:12:39 -
> @@ -350,7 +350,7 @@ dwiic_i2c_exec(void *cookie, i2c_op_t op
>   sc->sc_dev.dv_xname, __func__, tx_limit, x));
>  
>   if (flags & I2C_F_POLL) {
> - for (retries = 100; retries > 0; retries--) {
> + for (retries = 1000; retries > 0; retries--) {
>   rx_avail = dwiic_read(sc, DW_IC_RXFLR);
>   if (rx_avail > 0)
>   break;
> @@ -407,14 +407,13 @@ 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))
> + st = dwiic_read(sc, DW_IC_RAW_INTR_STAT);
> + if (st & DW_IC_INTR_STOP_DET)
>   break;
>   DELAY(1000);
>   }
> - if (st & DW_IC_STATUS_ACTIVITY)
> + if (!(st & DW_IC_INTR_STOP_DET))
>   printf("%s: timed out waiting for bus idle\n",
>   sc->sc_dev.dv_xname);
>   } else {
> 



Another dwiic(4) fix

2019-08-17 Thread Mark Kettenis
The timeout when waiting for data to be received for polled mode is
too small for taling to the BMC on the Ampere/Lenovo arm64 server.
This bumps it to 50 ms, which is still lower than what it is for
non-polled mode.

I also found that things worked much better if we checked for the
actually STOP detection bit to come instead of looking at the activity
bit in the status register.

Also tested on my Asus x205ta, which has an i2c keyboard.

ok?


Index: dwiic.c
===
RCS file: /cvs/src/sys/dev/ic/dwiic.c,v
retrieving revision 1.6
diff -u -p -r1.6 dwiic.c
--- dwiic.c 6 Aug 2019 06:56:29 -   1.6
+++ dwiic.c 17 Aug 2019 16:12:39 -
@@ -350,7 +350,7 @@ dwiic_i2c_exec(void *cookie, i2c_op_t op
sc->sc_dev.dv_xname, __func__, tx_limit, x));
 
if (flags & I2C_F_POLL) {
-   for (retries = 100; retries > 0; retries--) {
+   for (retries = 1000; retries > 0; retries--) {
rx_avail = dwiic_read(sc, DW_IC_RXFLR);
if (rx_avail > 0)
break;
@@ -407,14 +407,13 @@ 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))
+   st = dwiic_read(sc, DW_IC_RAW_INTR_STAT);
+   if (st & DW_IC_INTR_STOP_DET)
break;
DELAY(1000);
}
-   if (st & DW_IC_STATUS_ACTIVITY)
+   if (!(st & DW_IC_INTR_STOP_DET))
printf("%s: timed out waiting for bus idle\n",
sc->sc_dev.dv_xname);
} else {



Re: dwiic(4) fix

2018-05-24 Thread Bobby Johnson
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  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 
>> >
>> > 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.c19 Jan 2018 18:20:38 -  1.3
>> > > +++ dev/ic/dwiic.c21 May 2018 10:37:50 -
>> > > @@ -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

Re: dwiic(4) fix

2018-05-23 Thread Mike Larkin
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 
> > 
> > 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.c19 Jan 2018 18:20:38 -  1.3
> > > +++ dev/ic/dwiic.c21 May 2018 10:37:50 -
> > > @@ -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: t

Re: dwiic(4) fix

2018-05-22 Thread Remi Locherer
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 
> > 
> > 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.
> 


Looks fine on the Asus UX390UAK.
I don't notice a change with your diff applied. The touchpad still works.

Remi


OpenBSD 6.3-current (GENERIC.MP) #4: Tue May 22 22:16:21 CEST 2018
r...@typhoon.relo.ch:/usr/src/sys/arch/amd64/compile/GENERIC.MP
real mem = 17041674240 (16252MB)
avail mem = 16517115904 (15751MB)
mpath0 at root
scsibus0 at mpath0: 256 targets
mainbus0 at root
bios0 at mainbus0: SMBIOS rev. 3.0 @ 0x9b16d000 (31 entries)
bios0: vendor American Megatrends Inc. version "UX390UAK.312" date 04/25/2017
bios0: ASUSTeK COMPUTER INC. UX390UAK
acpi0 at bios0: rev 2
acpi0: sleep states S0 S3 S4 S5
acpi0: tables DSDT FACP APIC FPDT ECDT MCFG FIDT SSDT MSDM SSDT HPET UEFI SSDT 
LPIT WSMT SSDT SSDT DBGP DBG2 BGRT DMAR TPM2
acpi0: wakeup devices GLAN(S4) XHC_(S3) XDCI(S4) HDAS(S4)
acpitimer0 at acpi0: 3579545 Hz, 24 bits
acpimadt0 at acpi0 addr 0xfee0: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz, 2594.76 MHz
cpu0: 
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,SDBG,FMA3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,DEADLINE,AES,XSAVE,AVX,F16C,RDRAND,NXE,PAGE1GB,RDTSCP,LONG,LAHF,ABM,3DNOWP,PERF,ITSC,FSGSBASE,SGX,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,MPX,RDSEED,ADX,SMAP,CLFLUSHOPT,PT,IBRS,IBPB,STIBP,SENSOR,ARAT,MELTDOWN
cpu0: 256KB 64b/line 8-way L2 cache
cpu0: smt 0, core 0, package 0
mtrr: Pentium Pro MTRR support, 10 var ranges, 88 fixed ranges
cpu0: apic clock running at 23MHz
cpu0: mwait min=64, max=64, C-substates=0.2.1.2.4.1.1.1, IBE
cpu1 at mainbus0: apid 2 (application processor)
cpu1: Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz, 2593.93 MHz
cpu1: 
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,SDBG,FMA3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,DEADLINE,AES,XSAVE,AVX,F16C,RDRAND,NXE,PAGE1GB,RDTSCP,LONG,LAHF,ABM,3DNOWP,PERF,ITSC,FSGSBASE,SGX,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,MPX,RDSEED,ADX,SMAP,CLFLUSHOPT,PT,IBRS,IBPB,STIBP,SENSOR,ARAT,MELTDOWN
cpu1: 256KB 64b/line 8-way L2 cache
cpu1: smt 0, core 1, package 0
cpu2 at mainbus0: apid 1 (application processor)
cpu2: Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz, 2593.93 MHz
cpu2: 
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,SDBG,FMA3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,DEADLINE,AES,XSAVE,AVX,F16C,RDRAND,NXE,PAGE1GB,RDTSCP,LONG,LAHF,ABM,3DNOWP,PERF,ITSC,FSGSBASE,SGX,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,MPX,RDSEED,ADX,SMAP,CLFLUSHOPT,PT,IBRS,IBPB,STIBP,SENSOR,ARAT,MELTDOWN
cpu2: 256KB 64b/line 8-way L2 cache
cpu2: smt 1, core 0, package 0
cpu3 at mainbus0: apid 3 (application processor)
cpu3: Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz, 2593.93 MHz
cpu3: 
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,SDBG,FMA3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,DEADLINE,AES,XSAVE,AVX,F16C,RDRAND,NXE,PAGE1GB,RDTSCP,LONG,LAHF,ABM,3DNOWP,PERF,ITSC,FSGSBASE,SGX,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,MPX,RDSEED,ADX,SMAP,CLFLUSHOPT,PT,IBRS,IBPB,STIBP,SENSOR,ARAT,MELTDOWN
cpu3: 256KB 64b/line 8-way L2 cache
cpu3: smt 1, core 1, package 0
ioapic0 at mainbus0: apid 2 pa 0xfec0, version 20, 120 pins
acpiec0 at acpi0
acpimcfg0 at acpi0 addr 0xf000, bus 0-127
acpihpet0 at acpi0: 2399 Hz
acpiprt0 at acpi0: bus 0 (PCI0)
acpiprt1 at acpi0: bus -1 (PEG0)
acpiprt2 a

Re: dwiic(4) fix

2018-05-22 Thread Mark Kettenis
> Date: Mon, 21 May 2018 17:25:47 -0700
> From: Mike Larkin 
> 
> 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

> > 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 -  1.3
> > +++ dev/ic/dwiic.c  21 May 2018 10:37:50 -
> > @@ -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);
> > 

Re: dwiic(4) fix

2018-05-21 Thread Mike Larkin
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?

-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.c19 Jan 2018 18:20:38 -  1.3
> +++ dev/ic/dwiic.c21 May 2018 10:37:50 -
> @@ -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 (

dwiic(4) fix

2018-05-21 Thread Mark Kettenis
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?


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 -  1.3
+++ dev/ic/dwiic.c  21 May 2018 10:37:50 -
@@ -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);
}
}