Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 May 2017 08:16:47 +0000 (UTC)
From:      Wojciech Macek <wma@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r318521 - head/sys/dev/etherswitch/e6000sw
Message-ID:  <201705190816.v4J8GlaH002881@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: wma
Date: Fri May 19 08:16:47 2017
New Revision: 318521
URL: https://svnweb.freebsd.org/changeset/base/318521

Log:
  Improve busy-wait loop during switch phy access in e6000sw
  
  Hitherto implementation of PHY polling resulted in a risk of an
  endless loop and very high occupation of the SMI bus. Improve the
  operation by limiting the polling tries and adding sleepable
  pause.
  
  Submitted by: Marcin Wojtas <mw@semihalf.com>
  Obtained from: Semihalf
  Sponsored by: Stormshield
  Reviewed by: loos
  Differential revision: https://reviews.freebsd.org/D10713

Modified:
  head/sys/dev/etherswitch/e6000sw/e6000sw.c

Modified: head/sys/dev/etherswitch/e6000sw/e6000sw.c
==============================================================================
--- head/sys/dev/etherswitch/e6000sw/e6000sw.c	Fri May 19 08:11:15 2017	(r318520)
+++ head/sys/dev/etherswitch/e6000sw/e6000sw.c	Fri May 19 08:16:47 2017	(r318521)
@@ -431,13 +431,21 @@ out_fail:
 	return (err);
 }
 
-static __inline void
+static __inline int
 e6000sw_poll_done(e6000sw_softc_t *sc)
 {
+	int i;
+
+	for (i = 0; i < 16; i++) {
+
+		if (!(e6000sw_readreg(sc, REG_GLOBAL2, PHY_CMD) &
+		    (1 << PHY_CMD_SMI_BUSY)))
+			return (0);
 
-	while (e6000sw_readreg(sc, REG_GLOBAL2, PHY_CMD) &
-	    (1 << PHY_CMD_SMI_BUSY))
-		continue;
+		pause("e6000sw PHY poll", hz/1000);
+	}
+
+	return (ETIMEDOUT);
 }
 
 /*
@@ -449,6 +457,7 @@ e6000sw_readphy(device_t dev, int phy, i
 {
 	e6000sw_softc_t *sc;
 	uint32_t val;
+	int err;
 
 	sc = device_get_softc(dev);
 	val = 0;
@@ -460,14 +469,25 @@ e6000sw_readphy(device_t dev, int phy, i
 
 	E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
 
-	e6000sw_poll_done(sc);
+	err = e6000sw_poll_done(sc);
+	if (err != 0) {
+		device_printf(dev, "Timeout while waiting for switch\n");
+		return (err);
+	}
+
 	val |= 1 << PHY_CMD_SMI_BUSY;
 	val |= PHY_CMD_MODE_MDIO << PHY_CMD_MODE;
 	val |= PHY_CMD_OPCODE_READ << PHY_CMD_OPCODE;
 	val |= (reg << PHY_CMD_REG_ADDR) & PHY_CMD_REG_ADDR_MASK;
 	val |= (phy << PHY_CMD_DEV_ADDR) & PHY_CMD_DEV_ADDR_MASK;
 	e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG, val);
-	e6000sw_poll_done(sc);
+
+	err = e6000sw_poll_done(sc);
+	if (err != 0) {
+		device_printf(dev, "Timeout while waiting for switch\n");
+		return (err);
+	}
+
 	val = e6000sw_readreg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG)
 		& PHY_DATA_MASK;
 
@@ -479,6 +499,7 @@ e6000sw_writephy(device_t dev, int phy, 
 {
 	e6000sw_softc_t *sc;
 	uint32_t val;
+	int err;
 
 	sc = device_get_softc(dev);
 	val = 0;
@@ -490,7 +511,12 @@ e6000sw_writephy(device_t dev, int phy, 
 
 	E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
 
-	e6000sw_poll_done(sc);
+	err = e6000sw_poll_done(sc);
+	if (err != 0) {
+		device_printf(dev, "Timeout while waiting for switch\n");
+		return (err);
+	}
+
 	val |= PHY_CMD_MODE_MDIO << PHY_CMD_MODE;
 	val |= 1 << PHY_CMD_SMI_BUSY;
 	val |= PHY_CMD_OPCODE_WRITE << PHY_CMD_OPCODE;
@@ -499,7 +525,12 @@ e6000sw_writephy(device_t dev, int phy, 
 	e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG,
 			 data & PHY_DATA_MASK);
 	e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG, val);
-	e6000sw_poll_done(sc);
+
+	err = e6000sw_poll_done(sc);
+	if (err != 0) {
+		device_printf(dev, "Timeout while waiting for switch\n");
+		return (err);
+	}
 
 	return (0);
 }



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