Author: gonzo Date: Wed Aug 22 22:56:01 2018 New Revision: 338215 URL: https://svnweb.freebsd.org/changeset/base/338215
Log: [ig4] Fix I/O timeout issue with Designware I2C controller on AMD platforms Due to hardware limitation AMD I2C controller can't trigger pending interrupt if interrupt status has been changed after clearing interrupt status bits. So, I2C will lose the interrupt and IO will be timed out. Implements a workaround to disable I2C controller interrupt and re-enable I2C interrupt before existing interrupt handler. Submitted by: rajf...@gmail.com MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D16720 Modified: head/sys/dev/ichiic/ig4_acpi.c head/sys/dev/ichiic/ig4_iic.c head/sys/dev/ichiic/ig4_var.h Modified: head/sys/dev/ichiic/ig4_acpi.c ============================================================================== --- head/sys/dev/ichiic/ig4_acpi.c Wed Aug 22 22:19:42 2018 (r338214) +++ head/sys/dev/ichiic/ig4_acpi.c Wed Aug 22 22:56:01 2018 (r338215) @@ -68,10 +68,20 @@ static char *ig4iic_ids[] = { static int ig4iic_acpi_probe(device_t dev) { + ig4iic_softc_t *sc; + char *hid; - if (acpi_disabled("ig4iic") || - ACPI_ID_PROBE(device_get_parent(dev), dev, ig4iic_ids) == NULL) - return (ENXIO); + sc = device_get_softc(dev); + + if (acpi_disabled("ig4iic")) + return (ENXIO); + + hid = ACPI_ID_PROBE(device_get_parent(dev), dev, ig4iic_ids); + if (hid == NULL) + return (ENXIO); + + if (strcmp("AMDI0010", hid) == 0) + sc->access_intr_mask = 1; device_set_desc(dev, "Designware I2C Controller"); return (0); Modified: head/sys/dev/ichiic/ig4_iic.c ============================================================================== --- head/sys/dev/ichiic/ig4_iic.c Wed Aug 22 22:19:42 2018 (r338214) +++ head/sys/dev/ichiic/ig4_iic.c Wed Aug 22 22:56:01 2018 (r338215) @@ -724,6 +724,19 @@ ig4iic_intr(void *cookie) ++sc->rnext; status = reg_read(sc, IG4_REG_I2C_STA); } + + /* + * Workaround to trigger pending interrupt if IG4_REG_INTR_STAT + * is changed after clearing it + */ + if(sc->access_intr_mask) { + status = reg_read(sc, IG4_REG_INTR_MASK); + if(status) { + reg_write(sc, IG4_REG_INTR_MASK, 0); + reg_write(sc, IG4_REG_INTR_MASK, status); + } + } + wakeup(sc); mtx_unlock(&sc->io_lock); } Modified: head/sys/dev/ichiic/ig4_var.h ============================================================================== --- head/sys/dev/ichiic/ig4_var.h Wed Aug 22 22:19:42 2018 (r338214) +++ head/sys/dev/ichiic/ig4_var.h Wed Aug 22 22:56:01 2018 (r338215) @@ -72,6 +72,7 @@ struct ig4iic_softc { int slave_valid : 1; int read_started : 1; int write_started : 1; + int access_intr_mask : 1; /* * Locking semantics: _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"