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