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
This commit is contained in:
parent
2ba028b676
commit
3c8326d3d8
@ -108,6 +108,17 @@ set_controller(ig4iic_softc_t *sc, uint32_t ctl)
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user