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
This commit is contained in:
parent
9534fa80c9
commit
b854df5591
@ -431,13 +431,21 @@ out_fail:
|
||||
return (err);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
static __inline int
|
||||
e6000sw_poll_done(e6000sw_softc_t *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
while (e6000sw_readreg(sc, REG_GLOBAL2, PHY_CMD) &
|
||||
(1 << PHY_CMD_SMI_BUSY))
|
||||
continue;
|
||||
for (i = 0; i < 16; i++) {
|
||||
|
||||
if (!(e6000sw_readreg(sc, REG_GLOBAL2, PHY_CMD) &
|
||||
(1 << PHY_CMD_SMI_BUSY)))
|
||||
return (0);
|
||||
|
||||
pause("e6000sw PHY poll", hz/1000);
|
||||
}
|
||||
|
||||
return (ETIMEDOUT);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -449,6 +457,7 @@ e6000sw_readphy(device_t dev, int phy, int reg)
|
||||
{
|
||||
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, int reg)
|
||||
|
||||
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, int reg, int data)
|
||||
{
|
||||
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, int reg, int data)
|
||||
|
||||
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, int reg, int data)
|
||||
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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user