svn commit: r300990 - head/sys/dev/ichiic

Michael Gmelin grembo at FreeBSD.org
Mon May 30 09:05:26 UTC 2016


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);
 }


More information about the svn-src-head mailing list