From 5f5323a14cad19323060a8cbf9d96f2280a462dd Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:05:51 +0800 Subject: [PATCH 01/10] iopoll: introduce read_poll_timeout macro this macro is an extension of readx_poll_timeout macro. the accessor function op just supports only one parameter in the readx_poll_timeout macro, but this macro can supports multiple variable parameters for it. so functions like phy_read(struct phy_device *phydev, u32 regnum) and phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) can also use this poll timeout core. and also expand it can sleep some time before read operation. Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- include/linux/iopoll.h | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h index 35e15dfd4155..70f89b389648 100644 --- a/include/linux/iopoll.h +++ b/include/linux/iopoll.h @@ -13,6 +13,50 @@ #include #include +/** + * 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 @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 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(args); \ + if (cond) \ + break; \ + if (__timeout_us && \ + ktime_compare(ktime_get(), __timeout) > 0) { \ + (val) = op(args); \ + break; \ + } \ + if (__sleep_us) \ + usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + /** * 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) From eaa6b01024a74ab5f3064f17dd88596284f497c4 Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:05:52 +0800 Subject: [PATCH 02/10] iopoll: redefined readx_poll_timeout macro to simplify the code redefined readx_poll_timeout macro by read_poll_timeout to simplify the code. Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- include/linux/iopoll.h | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h index 70f89b389648..cb20c733b15a 100644 --- a/include/linux/iopoll.h +++ b/include/linux/iopoll.h @@ -76,25 +76,7 @@ * macros defined below rather than this macro directly. */ #define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us) \ -({ \ - 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); \ - for (;;) { \ - (val) = op(addr); \ - if (cond) \ - break; \ - if (__timeout_us && \ - ktime_compare(ktime_get(), __timeout) > 0) { \ - (val) = op(addr); \ - break; \ - } \ - if (__sleep_us) \ - usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ - } \ - (cond) ? 0 : -ETIMEDOUT; \ -}) + 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 From bd971ff0b73927b91f4520621d49d3a801ee4837 Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:05:53 +0800 Subject: [PATCH 03/10] net: phy: introduce phy_read_mmd_poll_timeout macro it is sometimes necessary to poll a phy register by phy_read_mmd() function until its value satisfies some condition. introduce phy_read_mmd_poll_timeout() macros that do this. Suggested-by: Andrew Lunn Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- include/linux/phy.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/phy.h b/include/linux/phy.h index 99b5e3c4b621..3984f375126e 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -787,6 +788,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. From 331c7372bd7a3ea452687d98e838067b3677f367 Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:05:54 +0800 Subject: [PATCH 04/10] net: phy: bcm84881: use phy_read_mmd_poll_timeout() to simplify the code use phy_read_mmd_poll_timeout() to replace the poll codes for simplify bcm84881_wait_init() function. Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- drivers/net/phy/bcm84881.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) 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; + int 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); - - 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) From 9c6464dcffa0ee42144c343f51aef3d26dbada05 Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:05:55 +0800 Subject: [PATCH 05/10] net: phy: aquantia: use phy_read_mmd_poll_timeout() to simplify the code use phy_read_mmd_poll_timeout() to replace the poll codes for simplify aqr107_wait_reset_complete() function. Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- drivers/net/phy/aquantia_main.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 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; + int val; - do { - val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID); - if (val < 0) - return val; - msleep(20); - } while (!val && --retries); - - 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) From 8964a2174f91a87b0858e8fb3018eaf06eaa0ede Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:05:56 +0800 Subject: [PATCH 06/10] net: phy: marvell10g: use phy_read_mmd_poll_timeout() to simplify the code use phy_read_mmd_poll_timeout() to replace the poll codes for simplify mv3310_reset() function. Suggested-by: Andrew Lunn Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- drivers/net/phy/marvell10g.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) 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) From fcbd30d09ba05389cb40cc1769b565df62aead35 Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:05:57 +0800 Subject: [PATCH 07/10] net: phy: introduce phy_read_poll_timeout macro it is sometimes necessary to poll a phy register by phy_read() function until its value satisfies some condition. introduce phy_read_poll_timeout() macros that do this. Suggested-by: Andrew Lunn Reviewed-by: Andrew Lunn Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- include/linux/phy.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/linux/phy.h b/include/linux/phy.h index 3984f375126e..2432ca463ddc 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -717,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 From 745a237c18f3f5bfe094e458f9bea5a72831ff1e Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:05:58 +0800 Subject: [PATCH 08/10] net: phy: use phy_read_poll_timeout() to simplify the code use phy_read_poll_timeout() to replace the poll codes for simplify the code in phy_poll_reset() function. Reviewed-by: Andrew Lunn Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) 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. */ From 7ae7ad2f11ef476b5e92f1d7dc4c5dd9194c4d5f Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:05:59 +0800 Subject: [PATCH 09/10] net: phy: smsc: use phy_read_poll_timeout() to simplify the code use phy_read_poll_timeout() to replace the poll codes for simplify lan87xx_read_status() function. Suggested-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- drivers/net/phy/smsc.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) 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); From 704f691a5fb33c461ed9a7b6abe115ae3c323691 Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Mon, 23 Mar 2020 23:06:00 +0800 Subject: [PATCH 10/10] net: phy: tja11xx: use phy_read_poll_timeout() to simplify the code use phy_read_poll_timeout() to replace the poll codes for simplify tja11xx_check() function. Suggested-by: Andrew Lunn Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Dejin Zheng Signed-off-by: David S. Miller --- drivers/net/phy/nxp-tja11xx.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) 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; + int val; - 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); - } - - 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,