diff options
-rw-r--r-- | drivers/net/phy/aquantia_main.c | 13 | ||||
-rw-r--r-- | drivers/net/phy/bcm84881.c | 27 | ||||
-rw-r--r-- | drivers/net/phy/marvell10g.c | 15 | ||||
-rw-r--r-- | drivers/net/phy/nxp-tja11xx.c | 16 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 16 | ||||
-rw-r--r-- | drivers/net/phy/smsc.c | 16 | ||||
-rw-r--r-- | include/linux/iopoll.h | 40 | ||||
-rw-r--r-- | include/linux/phy.h | 27 |
8 files changed, 86 insertions, 84 deletions
diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c index 837d5eaf9e76..41e7c1432497 100644 --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c @@ -434,16 +434,11 @@ static int aqr107_set_tunable(struct phy_device *phydev, */ static int aqr107_wait_reset_complete(struct phy_device *phydev) { - int val, retries = 100; - - do { - val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID); - if (val < 0) - return val; - msleep(20); - } while (!val && --retries); + int val; - return val ? 0 : -ETIMEDOUT; + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + VEND1_GLOBAL_FW_ID, val, val != 0, + 20000, 2000000, false); } static void aqr107_chip_info(struct phy_device *phydev) diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c index 14d55a77eb28..3840d2adbbb9 100644 --- a/drivers/net/phy/bcm84881.c +++ b/drivers/net/phy/bcm84881.c @@ -22,30 +22,11 @@ enum { static int bcm84881_wait_init(struct phy_device *phydev) { - unsigned int tries = 20; - int ret, val; - - do { - val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1); - if (val < 0) { - ret = val; - break; - } - if (!(val & MDIO_CTRL1_RESET)) { - ret = 0; - break; - } - if (!--tries) { - ret = -ETIMEDOUT; - break; - } - msleep(100); - } while (1); + int val; - if (ret) - phydev_err(phydev, "%s failed: %d\n", __func__, ret); - - return ret; + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, + val, !(val & MDIO_CTRL1_RESET), + 100000, 2000000, false); } static int bcm84881_config_init(struct phy_device *phydev) diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index 7e05b92504f0..7621badae64d 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -241,22 +241,17 @@ static int mv3310_power_up(struct phy_device *phydev) static int mv3310_reset(struct phy_device *phydev, u32 unit) { - int retries, val, err; + int val, err; err = phy_modify_mmd(phydev, MDIO_MMD_PCS, unit + MDIO_CTRL1, MDIO_CTRL1_RESET, MDIO_CTRL1_RESET); if (err < 0) return err; - retries = 20; - do { - msleep(5); - val = phy_read_mmd(phydev, MDIO_MMD_PCS, unit + MDIO_CTRL1); - if (val < 0) - return val; - } while (val & MDIO_CTRL1_RESET && --retries); - - return val & MDIO_CTRL1_RESET ? -ETIMEDOUT : 0; + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS, + unit + MDIO_CTRL1, val, + !(val & MDIO_CTRL1_RESET), + 5000, 100000, true); } static int mv3310_get_edpd(struct phy_device *phydev, u16 *edpd) diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c index b705d0bd798b..47caae770ffc 100644 --- a/drivers/net/phy/nxp-tja11xx.c +++ b/drivers/net/phy/nxp-tja11xx.c @@ -72,20 +72,10 @@ static struct tja11xx_phy_stats tja11xx_hw_stats[] = { static int tja11xx_check(struct phy_device *phydev, u8 reg, u16 mask, u16 set) { - int i, ret; - - for (i = 0; i < 200; i++) { - ret = phy_read(phydev, reg); - if (ret < 0) - return ret; - - if ((ret & mask) == set) - return 0; - - usleep_range(100, 150); - } + int val; - return -ETIMEDOUT; + return phy_read_poll_timeout(phydev, reg, val, (val & mask) == set, + 150, 30000, false); } static int phy_modify_check(struct phy_device *phydev, u8 reg, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index a585faf8b844..3b8f6b0b47b5 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1059,18 +1059,12 @@ EXPORT_SYMBOL(phy_disconnect); static int phy_poll_reset(struct phy_device *phydev) { /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ - unsigned int retries = 12; - int ret; - - do { - msleep(50); - ret = phy_read(phydev, MII_BMCR); - if (ret < 0) - return ret; - } while (ret & BMCR_RESET && --retries); - if (ret & BMCR_RESET) - return -ETIMEDOUT; + int ret, val; + ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), + 50000, 600000, true); + if (ret) + return ret; /* Some chips (smsc911x) may still need up to another 1ms after the * BMCR_RESET bit is cleared before they are usable. */ diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index b73298250793..93da7d3d0954 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -112,8 +112,6 @@ static int lan87xx_read_status(struct phy_device *phydev) int err = genphy_read_status(phydev); if (!phydev->link && priv->energy_enable) { - int i; - /* Disable EDPD to wake up PHY */ int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); if (rc < 0) @@ -125,15 +123,11 @@ static int lan87xx_read_status(struct phy_device *phydev) return rc; /* Wait max 640 ms to detect energy */ - for (i = 0; i < 64; i++) { - /* Sleep to allow link test pulses to be sent */ - msleep(10); - rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); - if (rc < 0) - return rc; - if (rc & MII_LAN83C185_ENERGYON) - break; - } + phy_read_poll_timeout(phydev, MII_LAN83C185_CTRL_STATUS, rc, + rc & MII_LAN83C185_ENERGYON, 10000, + 640000, true); + if (rc < 0) + return rc; /* Re-enable EDPD */ rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h index 35e15dfd4155..cb20c733b15a 100644 --- a/include/linux/iopoll.h +++ b/include/linux/iopoll.h @@ -14,36 +14,41 @@ #include <linux/io.h> /** - * readx_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs - * @op: accessor function (takes @addr as its only argument) - * @addr: Address to poll + * read_poll_timeout - Periodically poll an address until a condition is + * met or a timeout occurs + * @op: accessor function (takes @args as its arguments) * @val: Variable to read the value into * @cond: Break condition (usually involving @val) * @sleep_us: Maximum time to sleep between reads in us (0 * tight-loops). Should be less than ~20ms since usleep_range * is used (see Documentation/timers/timers-howto.rst). * @timeout_us: Timeout in us, 0 means never timeout + * @sleep_before_read: if it is true, sleep @sleep_us before read. + * @args: arguments for @op poll * * Returns 0 on success and -ETIMEDOUT upon a timeout. In either - * case, the last read value at @addr is stored in @val. Must not + * case, the last read value at @args is stored in @val. Must not * be called from atomic context if sleep_us or timeout_us are used. * * When available, you'll probably want to use one of the specialized * macros defined below rather than this macro directly. */ -#define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us) \ +#define read_poll_timeout(op, val, cond, sleep_us, timeout_us, \ + sleep_before_read, args...) \ ({ \ u64 __timeout_us = (timeout_us); \ unsigned long __sleep_us = (sleep_us); \ ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ might_sleep_if((__sleep_us) != 0); \ + if (sleep_before_read && __sleep_us) \ + usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ for (;;) { \ - (val) = op(addr); \ + (val) = op(args); \ if (cond) \ break; \ if (__timeout_us && \ ktime_compare(ktime_get(), __timeout) > 0) { \ - (val) = op(addr); \ + (val) = op(args); \ break; \ } \ if (__sleep_us) \ @@ -53,6 +58,27 @@ }) /** + * readx_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs + * @op: accessor function (takes @addr as its only argument) + * @addr: Address to poll + * @val: Variable to read the value into + * @cond: Break condition (usually involving @val) + * @sleep_us: Maximum time to sleep between reads in us (0 + * tight-loops). Should be less than ~20ms since usleep_range + * is used (see Documentation/timers/timers-howto.rst). + * @timeout_us: Timeout in us, 0 means never timeout + * + * Returns 0 on success and -ETIMEDOUT upon a timeout. In either + * case, the last read value at @addr is stored in @val. Must not + * be called from atomic context if sleep_us or timeout_us are used. + * + * When available, you'll probably want to use one of the specialized + * macros defined below rather than this macro directly. + */ +#define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us) \ + read_poll_timeout(op, val, cond, sleep_us, timeout_us, false, addr) + +/** * readx_poll_timeout_atomic - Periodically poll an address until a condition is met or a timeout occurs * @op: accessor function (takes @addr as its only argument) * @addr: Address to poll diff --git a/include/linux/phy.h b/include/linux/phy.h index 99b5e3c4b621..2432ca463ddc 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -24,6 +24,7 @@ #include <linux/mod_devicetable.h> #include <linux/u64_stats_sync.h> #include <linux/irqreturn.h> +#include <linux/iopoll.h> #include <linux/atomic.h> @@ -716,6 +717,19 @@ static inline int phy_read(struct phy_device *phydev, u32 regnum) return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, regnum); } +#define phy_read_poll_timeout(phydev, regnum, val, cond, sleep_us, \ + timeout_us, sleep_before_read) \ +({ \ + int __ret = read_poll_timeout(phy_read, val, (cond) || val < 0, \ + sleep_us, timeout_us, sleep_before_read, phydev, regnum); \ + if (val < 0) \ + __ret = val; \ + if (__ret) \ + phydev_err(phydev, "%s failed: %d\n", __func__, __ret); \ + __ret; \ +}) + + /** * __phy_read - convenience function for reading a given PHY register * @phydev: the phy_device struct @@ -787,6 +801,19 @@ static inline int __phy_modify_changed(struct phy_device *phydev, u32 regnum, */ int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum); +#define phy_read_mmd_poll_timeout(phydev, devaddr, regnum, val, cond, \ + sleep_us, timeout_us, sleep_before_read) \ +({ \ + int __ret = read_poll_timeout(phy_read_mmd, val, (cond) || val < 0, \ + sleep_us, timeout_us, sleep_before_read, \ + phydev, devaddr, regnum); \ + if (val < 0) \ + __ret = val; \ + if (__ret) \ + phydev_err(phydev, "%s failed: %d\n", __func__, __ret); \ + __ret; \ +}) + /** * __phy_read_mmd - Convenience function for reading a register * from an MMD on a given PHY. |