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>