Module Name:    src
Committed By:   jmcneill
Date:           Sun May 10 22:54:06 UTC 2015

Modified Files:
        src/sys/dev/i2c: at24cxx.c

Log Message:
Many I2C drivers hold spin locks between iic_acquire_bus / iic_release_bus.
Avoid sleeping while owning the I2C bus.


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/i2c/at24cxx.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/i2c/at24cxx.c
diff -u src/sys/dev/i2c/at24cxx.c:1.18 src/sys/dev/i2c/at24cxx.c:1.19
--- src/sys/dev/i2c/at24cxx.c:1.18	Fri Jul 25 08:10:37 2014
+++ src/sys/dev/i2c/at24cxx.c	Sun May 10 22:54:06 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: at24cxx.c,v 1.18 2014/07/25 08:10:37 dholland Exp $	*/
+/*	$NetBSD: at24cxx.c,v 1.19 2015/05/10 22:54:06 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: at24cxx.c,v 1.18 2014/07/25 08:10:37 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: at24cxx.c,v 1.19 2015/05/10 22:54:06 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -262,9 +262,6 @@ seeprom_read(dev_t dev, struct uio *uio,
 	 */
 
 	while (uio->uio_resid > 0 && uio->uio_offset < sc->sc_size) {
-		if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
-			return (error);
-
 		a = (int)uio->uio_offset;
 		if (sc->sc_cmdlen == 1) {
 			addr = sc->sc_address + (a >> 8);
@@ -274,6 +271,9 @@ seeprom_read(dev_t dev, struct uio *uio,
 			cmdbuf[0] = AT24CXX_ADDR_HI(a);
 			cmdbuf[1] = AT24CXX_ADDR_LO(a);
 		}
+
+		if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
+			return (error);
 		if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
 				      addr, cmdbuf, sc->sc_cmdlen,
 				      &ch, 1, 0)) != 0) {
@@ -282,11 +282,11 @@ seeprom_read(dev_t dev, struct uio *uio,
 			    "seeprom_read: byte read failed at 0x%x\n", a);
 			return (error);
 		}
+		iic_release_bus(sc->sc_tag, 0);
+
 		if ((error = uiomove(&ch, 1, uio)) != 0) {
-			iic_release_bus(sc->sc_tag, 0);
 			return (error);
 		}
-		iic_release_bus(sc->sc_tag, 0);
 	}
 
 	return (0);
@@ -313,9 +313,6 @@ seeprom_write(dev_t dev, struct uio *uio
 	 */
 
 	while (uio->uio_resid > 0 && uio->uio_offset < sc->sc_size) {
-		if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
-			return (error);
-
 		a = (int)uio->uio_offset;
 		if (sc->sc_cmdlen == 1) {
 			addr = sc->sc_address + (a >> 8);
@@ -329,6 +326,9 @@ seeprom_write(dev_t dev, struct uio *uio
 			iic_release_bus(sc->sc_tag, 0);
 			return (error);
 		}
+
+		if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
+			return (error);
 		if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
 				      addr, cmdbuf, sc->sc_cmdlen,
 				      &ch, 1, 0)) != 0) {
@@ -337,13 +337,12 @@ seeprom_write(dev_t dev, struct uio *uio
 			    "seeprom_write: byte write failed at 0x%x\n", a);
 			return (error);
 		}
+		iic_release_bus(sc->sc_tag, 0);
 
 		/* Wait until the device commits the byte. */
 		if ((error = seeprom_wait_idle(sc)) != 0) {
-			iic_release_bus(sc->sc_tag, 0);
 			return (error);
 		}
-		iic_release_bus(sc->sc_tag, 0);
 	}
 
 	return (0);
@@ -355,6 +354,7 @@ seeprom_wait_idle(struct seeprom_softc *
 	uint8_t cmdbuf[2] = { 0, 0 };
 	int rv, timeout;
 	u_int8_t dummy;
+	int error;
 
 	timeout = (1000 / hz) / AT24CXX_WRITE_CYCLE_MS;
 	if (timeout == 0)
@@ -366,8 +366,15 @@ seeprom_wait_idle(struct seeprom_softc *
 	 * Read the byte at address 0.  This is just a dummy
 	 * read to wait for the EEPROM's write cycle to complete.
 	 */
-	while (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address,
-			cmdbuf, sc->sc_cmdlen, &dummy, 1, 0)) {
+	for (;;) {
+		if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
+			return error;
+		error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+		    sc->sc_address, cmdbuf, sc->sc_cmdlen, &dummy, 1, 0);
+		iic_release_bus(sc->sc_tag, 0);
+		if (error == 0)
+			break;
+
 		rv = tsleep(sc, PRIBIO | PCATCH, "seepromwr", timeout);
 		if (rv != EWOULDBLOCK)
 			return (rv);

Reply via email to