On Sat, Mar 12, 2016 at 02:19:49PM +0100, Stefan Sperling wrote:
> On Fri, Mar 11, 2016 at 11:56:41AM -0700, Theo de Raadt wrote:
> > > But what we really should do the SMBALERT# dance of reading the Alert
> > > Response Address, which will make sure the device de-asserts the
> > > SMBALERT# line.
> > 
> > Ah, I did not check the spec.  That sounds very reasonable...
> 
> I've tried doing this without success.
> I'm getting a slave address in polling mode. It's always 0x0 which
> is not a valid address for a slave device. Most likely a bug in the
> crude changes I've made. Or perhaps the hardware is really triggering
> a bogus alert.

FWIW, these are the changes I used to test this approach.
This diff is most likely full of stupidity...

Prints 'ichiic0: alert from slave 0x0'.

Index: ichiic.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/ichiic.c,v
retrieving revision 1.37
diff -u -p -r1.37 ichiic.c
--- ichiic.c    7 Dec 2015 02:56:36 -0000       1.37
+++ ichiic.c    12 Mar 2016 13:05:39 -0000
@@ -25,6 +25,7 @@
 #include <sys/device.h>
 #include <sys/kernel.h>
 #include <sys/rwlock.h>
+#include <sys/task.h>
 
 #include <machine/bus.h>
 
@@ -52,6 +53,8 @@ struct ichiic_softc {
        bus_space_handle_t      sc_ioh;
        void *                  sc_ih;
        int                     sc_poll;
+       struct task             sc_alert_task;
+       int                     sc_task_added;
 
        struct i2c_controller   sc_i2c_tag;
        struct rwlock           sc_i2c_lock;
@@ -71,7 +74,8 @@ int   ichiic_i2c_acquire_bus(void *, int);
 void   ichiic_i2c_release_bus(void *, int);
 int    ichiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
            void *, size_t, int);
-
+void   ichiic_xfer_timeout(struct ichiic_softc *);
+void   ichiic_alert_task(void *);
 int    ichiic_intr(void *);
 
 struct cfattach ichiic_ca = {
@@ -178,6 +182,8 @@ ichiic_attach(struct device *parent, str
 
        printf("\n");
 
+       task_set(&sc->sc_alert_task, ichiic_alert_task, sc);
+
        /* Attach I2C bus */
        rw_init(&sc->sc_i2c_lock, "iiclk");
        sc->sc_i2c_tag.ic_cookie = sc;
@@ -316,6 +322,15 @@ ichiic_i2c_exec(void *cookie, i2c_op_t o
        return (0);
 
 timeout:
+       ichiic_xfer_timeout(sc);
+       return (1);
+
+}
+
+void ichiic_xfer_timeout(struct ichiic_softc *sc)
+{
+       u_int8_t st;
+
        /*
         * Transfer timeout. Kill the transaction and clear status bits.
         */
@@ -327,7 +342,69 @@ timeout:
                printf("%s: abort failed, status 0x%b\n",
                    sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS);
        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
-       return (1);
+}
+
+void
+ichiic_alert_task(void *arg)
+{
+       struct ichiic_softc *sc = arg;
+       int retries, s;
+       uint8_t st, ctl, slave_addr;
+
+       s = splbio();
+       /* Wait for bus to be idle */
+       for (retries = 100; retries > 0; retries--) {
+               st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
+               if (!(st & ICH_SMB_HS_BUSY))
+                       break;
+               DELAY(ICHIIC_DELAY);
+       }
+       printf("%s: alert: st 0x%b\n", sc->sc_dev.dv_xname, st,
+           ICH_SMB_HS_BITS);
+       if (st & ICH_SMB_HS_BUSY) {
+               splx(s);
+               return;
+       }
+
+       /* 
+        * Read the Alert Response Address.
+        * The device which pulled ALERT# will respond with its address.
+        */
+       bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_TXSLVA,
+           ICH_SMB_TXSLVA_ADDR(ICH_SMB_ARA) | ICH_SMB_TXSLVA_READ);
+       ctl = (ICH_SMB_HC_CMD_BDATA | ICH_SMB_HC_START);
+       bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ctl);
+
+       if (cold || sc->sc_poll) {
+               /* Poll for completion */
+               DELAY(ICHIIC_DELAY);
+               for (retries = 1000; retries > 0; retries--) {
+                       st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
+                           ICH_SMB_HS);
+                       if ((st & ICH_SMB_HS_BUSY) == 0)
+                               break;
+                       DELAY(ICHIIC_DELAY);
+               }
+               if (st & ICH_SMB_HS_BUSY)
+                       goto timeout;
+       } else {
+               /* Wait for interrupt */
+               if (tsleep(&sc->sc_alert_task, PRIBIO, "ichiica",
+                   ICHIIC_TIMEOUT * hz))
+                       goto timeout;
+       }
+
+       slave_addr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HD0);
+       printf("%s: alert from slave 0x%x\n", sc->sc_dev.dv_xname,
+           ICH_SMB_NDADDR_ADDR(slave_addr));
+
+       splx(s);
+       return;
+
+timeout:
+       ichiic_xfer_timeout(sc);
+       splx(s);
+       return;
 }
 
 int
@@ -348,6 +425,8 @@ ichiic_intr(void *arg)
 
        DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
            ICH_SMB_HS_BITS));
+       printf("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
+           ICH_SMB_HS_BITS);
 
        /* Clear status bits */
        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
@@ -373,8 +452,21 @@ ichiic_intr(void *arg)
                            ICH_SMB_HD1);
        }
 
+       if (st & ICH_SMB_HS_SMBAL) {
+               if (cold || sc->sc_poll)
+                       ichiic_alert_task(sc);
+               else {
+                       task_add(systq, &sc->sc_alert_task);
+                       sc->sc_task_added = 1;
+               }
+       }
+
 done:
        if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
                wakeup(sc);
+       if (sc->sc_task_added) {
+               wakeup(&sc->sc_alert_task);
+               sc->sc_task_added = 0;
+       }
        return (1);
 }
Index: ichreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/ichreg.h,v
retrieving revision 1.7
diff -u -p -r1.7 ichreg.h
--- ichreg.h    18 Dec 2005 12:09:04 -0000      1.7
+++ ichreg.h    12 Mar 2016 11:34:26 -0000
@@ -118,6 +118,8 @@
 #define ICH_SMB_NDLOW  0x16            /* notify data low byte */
 #define ICH_SMB_NDHIGH 0x17            /* notify data high byte */
 
+#define ICH_SMB_ARA    0x0c            /* alert response address */
+
 /*
  * 6300ESB watchdog timer registers.
  */

Reply via email to