Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Aug 2018 22:56:02 +0000 (UTC)
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r338215 - head/sys/dev/ichiic
Message-ID:  <201808222256.w7MMu2Hl070070@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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:	rajfbsd@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:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808222256.w7MMu2Hl070070>