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

Vladimir Kondratyev wulf at FreeBSD.org
Sun Nov 3 20:42:05 UTC 2019


Author: wulf
Date: Sun Nov  3 20:42:04 2019
New Revision: 354293
URL: https://svnweb.freebsd.org/changeset/base/354293

Log:
  [ig4] Only enable interrupts when we want them. Otherwise keep mask at 0.
  
  This avoids possible interrupt storms, depending on the state of the I2C
  controller before the driver attached.
  
  During attaching this clears the interrupt mask.
  
  Revert r338215 as this change makes it no-op.
  
  Obtained from:	DragonflyBSD (d7c8555)

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	Sun Nov  3 20:40:55 2019	(r354292)
+++ head/sys/dev/ichiic/ig4_acpi.c	Sun Nov  3 20:42:04 2019	(r354293)
@@ -69,18 +69,15 @@ static int
 ig4iic_acpi_probe(device_t dev)
 {
 	ig4iic_softc_t *sc;
-	char *hid;
 	int rv;
 
 	sc = device_get_softc(dev);
 	if (acpi_disabled("ig4iic"))
 		return (ENXIO);
-	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, ig4iic_ids, &hid);
+	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, ig4iic_ids, NULL);
 	if (rv > 0)
 		return (rv);
 
-        if (strcmp("AMDI0010", hid) == 0)
-                sc->access_intr_mask = 1;
 	device_set_desc(dev, "Designware I2C Controller");
 	return (rv);
 }

Modified: head/sys/dev/ichiic/ig4_iic.c
==============================================================================
--- head/sys/dev/ichiic/ig4_iic.c	Sun Nov  3 20:40:55 2019	(r354292)
+++ head/sys/dev/ichiic/ig4_iic.c	Sun Nov  3 20:42:04 2019	(r354293)
@@ -98,6 +98,15 @@ reg_read(ig4iic_softc_t *sc, uint32_t reg)
 	return (value);
 }
 
+static void
+set_intr_mask(ig4iic_softc_t *sc, uint32_t val)
+{
+	if (sc->intr_mask != val) {
+		reg_write(sc, IG4_REG_INTR_MASK, val);
+		sc->intr_mask = val;
+	}
+}
+
 /*
  * Enable or disable the controller and wait for the controller to acknowledge
  * the state change.
@@ -113,12 +122,9 @@ set_controller(ig4iic_softc_t *sc, uint32_t ctl)
 	 * 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);
+	set_intr_mask(sc, 0);
+	if (ctl & IG4_I2C_ENABLE)
 		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 = IIC_ETIMEOUT;
@@ -196,8 +202,10 @@ wait_status(ig4iic_softc_t *sc, uint32_t status)
 		 * work, otherwise poll with the lock held.
 		 */
 		if (status & IG4_STATUS_RX_NOTEMPTY) {
+			set_intr_mask(sc, IG4_INTR_STOP_DET | IG4_INTR_RX_FULL);
 			mtx_sleep(sc, &sc->io_lock, 0, "i2cwait",
 				  (hz + 99) / 100); /* sleep up to 10ms */
+			set_intr_mask(sc, 0);
 			count_us += 10000;
 		} else {
 			DELAY(25);
@@ -579,6 +587,10 @@ ig4iic_attach(ig4iic_softc_t *sc)
 	v = reg_read(sc, IG4_REG_SS_SCL_LCNT);
 	reg_write(sc, IG4_REG_FS_SCL_LCNT, v);
 
+	reg_read(sc, IG4_REG_CLR_INTR);
+	reg_write(sc, IG4_REG_INTR_MASK, 0);
+	sc->intr_mask = 0;
+
 	/*
 	 * Program based on a 25000 Hz clock.  This is a bit of a
 	 * hack (obviously).  The defaults are 400 and 470 for standard
@@ -725,7 +737,7 @@ ig4iic_intr(void *cookie)
 	uint32_t status;
 
 	mtx_lock(&sc->io_lock);
-/*	reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET);*/
+	set_intr_mask(sc, 0);
 	reg_read(sc, IG4_REG_CLR_INTR);
 	status = reg_read(sc, IG4_REG_I2C_STA);
 	while (status & IG4_STATUS_RX_NOTEMPTY) {
@@ -733,18 +745,6 @@ ig4iic_intr(void *cookie)
 		    (uint8_t)reg_read(sc, IG4_REG_DATA_CMD);
 		++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 != 0) {
-		status = reg_read(sc, IG4_REG_INTR_MASK);
-		if (status != 0) {
-			reg_write(sc, IG4_REG_INTR_MASK, 0);
-			reg_write(sc, IG4_REG_INTR_MASK, status);
-		}
 	}
 
 	wakeup(sc);

Modified: head/sys/dev/ichiic/ig4_var.h
==============================================================================
--- head/sys/dev/ichiic/ig4_var.h	Sun Nov  3 20:40:55 2019	(r354292)
+++ head/sys/dev/ichiic/ig4_var.h	Sun Nov  3 20:42:04 2019	(r354293)
@@ -65,6 +65,7 @@ struct ig4iic_softc {
 	int		rnext;
 	int		rpos;
 	char		rbuf[IG4_RBUFSIZE];
+	uint32_t	intr_mask;
 	int		error;
 	uint8_t		last_slave;
 	int		platform_attached : 1;
@@ -72,7 +73,6 @@ struct ig4iic_softc {
 	int		slave_valid : 1;
 	int		read_started : 1;
 	int		write_started : 1;
-	int		access_intr_mask : 1;
 
 	/*
 	 * Locking semantics:


More information about the svn-src-all mailing list