Commit 629cb919 authored by David S. Miller's avatar David S. Miller

Merge branch 'introduce-read_poll_timeout'

Dejin Zheng says:

====================
introduce read_poll_timeout

This patch sets is introduce read_poll_timeout macro, it 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
use this poll timeout framework.

the first patch introduce read_poll_timeout macro, and the second patch
redefined readx_poll_timeout macro by read_poll_timeout(), and the other
patches are examples using read_poll_timeout macro.

v6 -> v7:
	- add a parameter to supports that it can sleep some time
	  before read operation in read_poll_timeout macro.
	- add prefix with double underscores for some variable to avoid
	  any variable re-declaration or shadowing in patch 3 and patch
	  7.
v5 -> v6:
	- add some check to keep the code more similar in patch 8
v4 -> v5:
	- add some msleep() before call phy_read_mmd_poll_timeout() to
	  keep the code more similar in patch 6 and patch 9.
	- add a patch of drop by v4, it can add msleep before call
	  phy_read_poll_timeout() to keep the code more similar.
v3 -> v4:
	- add 3 examples of using new functions.
	- deal with precedence issues for parameter cond.
	- drop a patch about phy_poll_reset() function.
v2 -> v3:
	- modify the parameter order of newly added functions.
	  phy_read_mmd_poll_timeout(val, cond, sleep_us, timeout_us, \
				     phydev, devaddr, regnum)
				||
				\/
	  phy_read_mmd_poll_timeout(phydev, devaddr regnum, val, cond, \
				    sleep_us, timeout_us)

	  phy_read_poll_timeout(val, cond, sleep_us, timeout_us, \
				phydev, regnum)
				||
				\/
	  phy_read_poll_timeout(phydev, regnum, val, cond, sleep_us, \
				timeout_us)
v1 -> v2:
	- passed a phydev, device address and a reg to replace args...
	  parameter in phy_read_mmd_poll_timeout() by Andrew Lunn 's
	  suggestion in patch 3. Andrew Lunn <andrew@lunn.ch>, Thanks
	  very much for your help!
	- also in patch 3, handle phy_read_mmd return an error(the return
	  value < 0) in phy_read_mmd_poll_timeout(). Thanks Andrew
	  again.
	- in patch 6, pass a phydev and a reg to replace args...
	  parameter in phy_read_poll_timeout(), and also handle the
	  phy_read() function's return error.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents af13b3c3 704f691a
...@@ -434,16 +434,11 @@ static int aqr107_set_tunable(struct phy_device *phydev, ...@@ -434,16 +434,11 @@ static int aqr107_set_tunable(struct phy_device *phydev,
*/ */
static int aqr107_wait_reset_complete(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) static void aqr107_chip_info(struct phy_device *phydev)
......
...@@ -22,30 +22,11 @@ enum { ...@@ -22,30 +22,11 @@ enum {
static int bcm84881_wait_init(struct phy_device *phydev) static int bcm84881_wait_init(struct phy_device *phydev)
{ {
unsigned int tries = 20; int val;
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);
if (ret) return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
phydev_err(phydev, "%s failed: %d\n", __func__, ret); val, !(val & MDIO_CTRL1_RESET),
100000, 2000000, false);
return ret;
} }
static int bcm84881_config_init(struct phy_device *phydev) static int bcm84881_config_init(struct phy_device *phydev)
......
...@@ -241,22 +241,17 @@ static int mv3310_power_up(struct phy_device *phydev) ...@@ -241,22 +241,17 @@ static int mv3310_power_up(struct phy_device *phydev)
static int mv3310_reset(struct phy_device *phydev, u32 unit) 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, err = phy_modify_mmd(phydev, MDIO_MMD_PCS, unit + MDIO_CTRL1,
MDIO_CTRL1_RESET, MDIO_CTRL1_RESET); MDIO_CTRL1_RESET, MDIO_CTRL1_RESET);
if (err < 0) if (err < 0)
return err; return err;
retries = 20; return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS,
do { unit + MDIO_CTRL1, val,
msleep(5); !(val & MDIO_CTRL1_RESET),
val = phy_read_mmd(phydev, MDIO_MMD_PCS, unit + MDIO_CTRL1); 5000, 100000, true);
if (val < 0)
return val;
} while (val & MDIO_CTRL1_RESET && --retries);
return val & MDIO_CTRL1_RESET ? -ETIMEDOUT : 0;
} }
static int mv3310_get_edpd(struct phy_device *phydev, u16 *edpd) static int mv3310_get_edpd(struct phy_device *phydev, u16 *edpd)
......
...@@ -72,20 +72,10 @@ static struct tja11xx_phy_stats tja11xx_hw_stats[] = { ...@@ -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) 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, static int phy_modify_check(struct phy_device *phydev, u8 reg,
......
...@@ -1059,18 +1059,12 @@ EXPORT_SYMBOL(phy_disconnect); ...@@ -1059,18 +1059,12 @@ EXPORT_SYMBOL(phy_disconnect);
static int phy_poll_reset(struct phy_device *phydev) static int phy_poll_reset(struct phy_device *phydev)
{ {
/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
unsigned int retries = 12; int ret, val;
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;
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 /* Some chips (smsc911x) may still need up to another 1ms after the
* BMCR_RESET bit is cleared before they are usable. * BMCR_RESET bit is cleared before they are usable.
*/ */
......
...@@ -112,8 +112,6 @@ static int lan87xx_read_status(struct phy_device *phydev) ...@@ -112,8 +112,6 @@ static int lan87xx_read_status(struct phy_device *phydev)
int err = genphy_read_status(phydev); int err = genphy_read_status(phydev);
if (!phydev->link && priv->energy_enable) { if (!phydev->link && priv->energy_enable) {
int i;
/* Disable EDPD to wake up PHY */ /* Disable EDPD to wake up PHY */
int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
if (rc < 0) if (rc < 0)
...@@ -125,15 +123,11 @@ static int lan87xx_read_status(struct phy_device *phydev) ...@@ -125,15 +123,11 @@ static int lan87xx_read_status(struct phy_device *phydev)
return rc; return rc;
/* Wait max 640 ms to detect energy */ /* Wait max 640 ms to detect energy */
for (i = 0; i < 64; i++) { phy_read_poll_timeout(phydev, MII_LAN83C185_CTRL_STATUS, rc,
/* Sleep to allow link test pulses to be sent */ rc & MII_LAN83C185_ENERGYON, 10000,
msleep(10); 640000, true);
rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); if (rc < 0)
if (rc < 0) return rc;
return rc;
if (rc & MII_LAN83C185_ENERGYON)
break;
}
/* Re-enable EDPD */ /* Re-enable EDPD */
rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
......
...@@ -14,36 +14,41 @@ ...@@ -14,36 +14,41 @@
#include <linux/io.h> #include <linux/io.h>
/** /**
* readx_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs * read_poll_timeout - Periodically poll an address until a condition is
* @op: accessor function (takes @addr as its only argument) * met or a timeout occurs
* @addr: Address to poll * @op: accessor function (takes @args as its arguments)
* @val: Variable to read the value into * @val: Variable to read the value into
* @cond: Break condition (usually involving @val) * @cond: Break condition (usually involving @val)
* @sleep_us: Maximum time to sleep between reads in us (0 * @sleep_us: Maximum time to sleep between reads in us (0
* tight-loops). Should be less than ~20ms since usleep_range * tight-loops). Should be less than ~20ms since usleep_range
* is used (see Documentation/timers/timers-howto.rst). * is used (see Documentation/timers/timers-howto.rst).
* @timeout_us: Timeout in us, 0 means never timeout * @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 * 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. * 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 * When available, you'll probably want to use one of the specialized
* macros defined below rather than this macro directly. * 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); \ u64 __timeout_us = (timeout_us); \
unsigned long __sleep_us = (sleep_us); \ unsigned long __sleep_us = (sleep_us); \
ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
might_sleep_if((__sleep_us) != 0); \ might_sleep_if((__sleep_us) != 0); \
if (sleep_before_read && __sleep_us) \
usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
for (;;) { \ for (;;) { \
(val) = op(addr); \ (val) = op(args); \
if (cond) \ if (cond) \
break; \ break; \
if (__timeout_us && \ if (__timeout_us && \
ktime_compare(ktime_get(), __timeout) > 0) { \ ktime_compare(ktime_get(), __timeout) > 0) { \
(val) = op(addr); \ (val) = op(args); \
break; \ break; \
} \ } \
if (__sleep_us) \ if (__sleep_us) \
...@@ -52,6 +57,27 @@ ...@@ -52,6 +57,27 @@
(cond) ? 0 : -ETIMEDOUT; \ (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)
* @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 * 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) * @op: accessor function (takes @addr as its only argument)
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/u64_stats_sync.h> #include <linux/u64_stats_sync.h>
#include <linux/irqreturn.h> #include <linux/irqreturn.h>
#include <linux/iopoll.h>
#include <linux/atomic.h> #include <linux/atomic.h>
...@@ -716,6 +717,19 @@ static inline int phy_read(struct phy_device *phydev, u32 regnum) ...@@ -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); 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 * __phy_read - convenience function for reading a given PHY register
* @phydev: the phy_device struct * @phydev: the phy_device struct
...@@ -787,6 +801,19 @@ static inline int __phy_modify_changed(struct phy_device *phydev, u32 regnum, ...@@ -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); 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 * __phy_read_mmd - Convenience function for reading a register
* from an MMD on a given PHY. * from an MMD on a given PHY.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment