Author: grembo (ports committer)
Date: Mon May 30 09:05:24 2016
New Revision: 300990
URL: https://svnweb.freebsd.org/changeset/base/300990

Log:
  Fix ig4 operation for certain machines
  
  Some machine BIOSes use the I2C bus and leave it in a state that causes
  interrupts to not work properly due to a pending interrupt having been
  latched.
  
  Refactor the code a bit to clear pending interrupts when I2C is enabled.
  This fixes the primary problem.
  
  Also fix a possible race condition in the interrupt handler where the
  interrupt was being cleared after reading the status instead of before.
  
  Reported by:  pfg
  Reviewed by:  jhb
  Approved by:  jhb
  Obtained from:        DragonFly BSD
  Differential Revision:        https://reviews.freebsd.org/D6586

Modified:
  head/sys/dev/ichiic/ig4_iic.c

Modified: head/sys/dev/ichiic/ig4_iic.c
==============================================================================
--- head/sys/dev/ichiic/ig4_iic.c       Mon May 30 08:50:33 2016        
(r300989)
+++ head/sys/dev/ichiic/ig4_iic.c       Mon May 30 09:05:24 2016        
(r300990)
@@ -108,6 +108,17 @@ set_controller(ig4iic_softc_t *sc, uint3
        int error;
        uint32_t v;
 
+       /*
+        * When the controller is enabled, interrupt on STOP detect
+        * or receive character ready and clear pending interrupts.
+        */
+       if (ctl & IG4_I2C_ENABLE) {
+               reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET |
+                                                IG4_INTR_RX_FULL);
+               reg_read(sc, IG4_REG_CLR_INTR);
+       } else
+               reg_write(sc, IG4_REG_INTR_MASK, 0);
+
        reg_write(sc, IG4_REG_I2C_EN, ctl);
        error = SMB_ETIMEOUT;
 
@@ -553,11 +564,6 @@ ig4iic_attach(ig4iic_softc_t *sc)
        reg_write(sc, IG4_REG_RESETS, IG4_RESETS_DEASSERT);
 #endif
 
-       /*
-        * Interrupt on STOP detect or receive character ready
-        */
-       reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET |
-                                        IG4_INTR_RX_FULL);
        mtx_lock(&sc->io_lock);
        if (set_controller(sc, 0))
                device_printf(sc->dev, "controller error during attach-1\n");
@@ -574,7 +580,8 @@ ig4iic_attach(ig4iic_softc_t *sc)
        sc->enum_hook.ich_func = ig4iic_start;
        sc->enum_hook.ich_arg = sc->dev;
 
-       /* We have to wait until interrupts are enabled. I2C read and write
+       /*
+        * We have to wait until interrupts are enabled. I2C read and write
         * only works if the interrupts are available.
         */
        if (config_intrhook_establish(&sc->enum_hook) != 0)
@@ -628,7 +635,6 @@ ig4iic_detach(ig4iic_softc_t *sc)
        sc->smb = NULL;
        sc->intr_handle = NULL;
        reg_write(sc, IG4_REG_INTR_MASK, 0);
-       reg_read(sc, IG4_REG_CLR_INTR);
        set_controller(sc, 0);
 
        mtx_unlock(&sc->io_lock);
@@ -917,6 +923,7 @@ ig4iic_intr(void *cookie)
 
        mtx_lock(&sc->io_lock);
 /*     reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET);*/
+       reg_read(sc, IG4_REG_CLR_INTR);
        status = reg_read(sc, IG4_REG_I2C_STA);
        while (status & IG4_STATUS_RX_NOTEMPTY) {
                sc->rbuf[sc->rnext & IG4_RBUFMASK] =
@@ -924,7 +931,6 @@ ig4iic_intr(void *cookie)
                ++sc->rnext;
                status = reg_read(sc, IG4_REG_I2C_STA);
        }
-       reg_read(sc, IG4_REG_CLR_INTR);
        wakeup(sc);
        mtx_unlock(&sc->io_lock);
 }
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to