2020-03-23 15:07:27

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 00/10] 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 <[email protected]>, 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.

Dejin Zheng (10):
iopoll: introduce read_poll_timeout macro
iopoll: redefined readx_poll_timeout macro to simplify the code
net: phy: introduce phy_read_mmd_poll_timeout macro
net: phy: bcm84881: use phy_read_mmd_poll_timeout() to simplify the
code
net: phy: aquantia: use phy_read_mmd_poll_timeout() to simplify the
code
net: phy: marvell10g: use phy_read_mmd_poll_timeout() to simplify the
code
net: phy: introduce phy_read_poll_timeout macro
net: phy: use phy_read_poll_timeout() to simplify the code
net: phy: smsc: use phy_read_poll_timeout() to simplify the code
net: phy: tja11xx: use phy_read_poll_timeout() to simplify the code

drivers/net/phy/aquantia_main.c | 13 ++++-------
drivers/net/phy/bcm84881.c | 27 ++++------------------
drivers/net/phy/marvell10g.c | 15 +++++--------
drivers/net/phy/nxp-tja11xx.c | 16 +++----------
drivers/net/phy/phy_device.c | 16 +++++--------
drivers/net/phy/smsc.c | 16 +++++--------
include/linux/iopoll.h | 40 +++++++++++++++++++++++++++------
include/linux/phy.h | 27 ++++++++++++++++++++++
8 files changed, 86 insertions(+), 84 deletions(-)

--
2.25.0


2020-03-23 15:07:35

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
---
v6 -> v7:
- add a parameter sleep_before_read to support that it can sleep
some time before read operation in read_poll_timeout macro.
v5 -> v6:
- no changed
v4 -> v5:
- no changed
v3 -> v4:
- no changed
v2 -> v3:
- no changed
v1 -> v2:
- no changed

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 <linux/errno.h>
#include <linux/io.h>

+/**
+ * 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)
--
2.25.0

2020-03-23 15:07:39

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
---
v6 -> v7:
- adapt to a newly added parameter sleep_before_read.
v5 -> v6:
- no changed
v4 -> v5:
- no changed
v3 -> v4:
- no changed
v2 -> v3:
- no changed
v1 -> v2:
- no changed

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
--
2.25.0

2020-03-23 15:08:07

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
Reviewed-by: Andrew Lunn <[email protected]>
Reviewed-by: Florian Fainelli <[email protected]>
Signed-off-by: Dejin Zheng <[email protected]>
---
v6 -> v7:
- adapt to a newly added parameter sleep_before_read.
- add prefix with double underscores for the variable ret to avoid
any variable re-declaration or shadowing.
v5 -> v6:
- no changed
v4 -> v5:
- no changed
v3 -> v4:
- deal with precedence issues for parameter cond.
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)
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. Andrew Lunn <[email protected]>, Thanks very much for
your help!
- handle phy_read_mmd return an error(the return value < 0) in
phy_read_mmd_poll_timeout(). Thanks Andrew again.

include/linux/phy.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/include/linux/phy.h b/include/linux/phy.h
index 36d9dea04016..c172747b4ab2 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>

@@ -784,6 +785,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.
--
2.25.0

2020-03-23 15:08:12

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
Reviewed-by: Florian Fainelli <[email protected]>
Signed-off-by: Dejin Zheng <[email protected]>
---
v6 -> v7:
- adapt to a newly added parameter sleep_before_read.
v5 -> v6:
- no changed
v4 -> v5:
- no changed
v3 -> v4:
- no changed
v2 -> v3:
- adapt to it after modifying the parameter order of the
newly added function
v1 -> v2:
- remove the handle of phy_read_mmd's return error.

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;
-
- 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)
--
2.25.0

2020-03-23 15:08:18

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
Reviewed-by: Florian Fainelli <[email protected]>
Signed-off-by: Dejin Zheng <[email protected]>
---
v6 -> v7:
- adapt to a newly added parameter sleep_before_read.
v5 -> v6:
- no changed
v4 -> v5:
- no changed
v3 -> v4:
- no changed
v2 -> v3:
- adapt to it after modifying the parameter order of the
newly added function
v1 -> v2:
- remove the handle of phy_read_mmd's return error.


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 31927b2c7d5a..d6829839ba60 100644
--- a/drivers/net/phy/aquantia_main.c
+++ b/drivers/net/phy/aquantia_main.c
@@ -451,16 +451,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)
--
2.25.0

2020-03-23 15:08:31

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
Signed-off-by: Dejin Zheng <[email protected]>
---
v6 -> v7:
- adapt to a newly added parameter sleep_before_read.
v5 -> v6:
- no changed.
v4 -> v5:
- add msleep() to before call phy_read_mmd_poll_timeout()
to keep the code more similar.
v3 -> v4:
- add this patch by Andrew's suggestion. Thanks Andrew!


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)
--
2.25.0

2020-03-23 15:08:51

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
Signed-off-by: Dejin Zheng <[email protected]>
---
v6 -> v7:
- adapt to a newly added parameter sleep_before_read.
v5 -> v6:
- add some check for keep the code more similar.
v4 -> v5:
- it can add msleep before call phy_read_poll_timeout()
to keep the code more similar. so add it.
v3 -> v4:
- drop it.
v2 -> v3:
- adapt to it after modifying the parameter order of the
newly added function
v1 -> v2:
- remove the handle of phy_read()'s return error.

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.
*/
--
2.25.0

2020-03-23 15:09:01

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
Reviewed-by: Florian Fainelli <[email protected]>
Signed-off-by: Dejin Zheng <[email protected]>
---
v6 -> v7:
- adapt to a newly added parameter sleep_before_read.
v5 -> v6:
- no changed.
v4 -> v5:
- add msleep before phy_read_poll_timeout() to keep the
code more similar
v3 -> v4:
- add this patch by Andrew's suggestion. Thanks Andrew!

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);
--
2.25.0

2020-03-23 15:09:09

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
Reviewed-by: Andrew Lunn <[email protected]>
Reviewed-by: Florian Fainelli <[email protected]>
Signed-off-by: Dejin Zheng <[email protected]>
---
v6 -> v7:
- adapt to a newly added parameter sleep_before_read.
v5 -> v6:
- no changed.
v4 -> v5:
- no changed.
v3 -> v4:
- add this patch by Andrew's suggestion. Thanks Andrew!

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;
-
- 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,
--
2.25.0

2020-03-23 15:09:38

by Dejin Zheng

[permalink] [raw]
Subject: [PATCH net-next v7 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 <[email protected]>
Reviewed-by: Andrew Lunn <[email protected]>
Signed-off-by: Dejin Zheng <[email protected]>
---
v6 -> v7:
- adapt to a newly added parameter sleep_before_read.
- add prefix with double underscores for the variable ret to avoid
any variable re-declaration or shadowing.
v5 -> v6:
- no changed.
v4 -> v5:
- no changed.
v3 -> v4:
- deal with precedence issues for parameter cond.
v2 -> v3:
- modify the parameter order of newly added functions.
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:
- pass a phydev and a regnum to replace args... parameter in
the phy_read_poll_timeout(), and also handle the
phy_read() function's return error.

include/linux/phy.h | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/include/linux/phy.h b/include/linux/phy.h
index c172747b4ab2..4f5b9dbc551d 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -714,6 +714,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
--
2.25.0

2020-03-24 05:01:08

by David Miller

[permalink] [raw]
Subject: Re: [PATCH net-next v7 00/10] introduce read_poll_timeout

From: Dejin Zheng <[email protected]>
Date: Mon, 23 Mar 2020 23:05:50 +0800

> 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.
...

Series applied, thanks.

2020-06-01 19:09:55

by Kevin Groeneveld

[permalink] [raw]
Subject: Re: [PATCH net-next v7 09/10] net: phy: smsc: use phy_read_poll_timeout() to simplify the code

Resent as plain text this time. Sorry to those that got this twice.

On Mon, Mar 23, 2020 at 11:10 AM Dejin Zheng <[email protected]> wrote:
>
> use phy_read_poll_timeout() to replace the poll codes for
> simplify lan87xx_read_status() function.
>
> Suggested-by: Andrew Lunn <[email protected]>
> Reviewed-by: Florian Fainelli <[email protected]>
> Signed-off-by: Dejin Zheng <[email protected]>
> ---
> v6 -> v7:
> - adapt to a newly added parameter sleep_before_read.
> v5 -> v6:
> - no changed.
> v4 -> v5:
> - add msleep before phy_read_poll_timeout() to keep the
> code more similar
> v3 -> v4:
> - add this patch by Andrew's suggestion. Thanks Andrew!
>
> 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);
> --
> 2.25.0

This patch causes the kernel log to be spammed with the following when
Ethernet cable is not connected:
SMSC LAN8710/LAN8720 2188000.ethernet-1:00: lan87xx_read_status failed: -110

It still seems to work but I think that is only a fluke.

The "if (rc < 0)" is not actually checking the return value of
phy_read_poll_timeout but is looking at the value of the register
read. I don't think rc will ever be negative in this case. If you
change the code to "rc = phy_read_poll_timeout(...)" so that it
actually checks the error then the function will behave differently
than before. The original code would only return an error if phy_read
returned an error. On a timeout it just continued. So the "if" could
be changed to "if (rc < 0 && rc != -ETIMEDOUT)". But you will still
get the extra messages in the log that were not there before.

Kevin

2020-06-02 16:32:45

by Dejin Zheng

[permalink] [raw]
Subject: Re: [PATCH net-next v7 09/10] net: phy: smsc: use phy_read_poll_timeout() to simplify the code

On Mon, Jun 01, 2020 at 02:58:21PM -0400, Kevin Groeneveld wrote:
> On Mon, Mar 23, 2020 at 11:10 AM Dejin Zheng <[email protected]> wrote:
> >
> > use phy_read_poll_timeout() to replace the poll codes for
> > simplify lan87xx_read_status() function.
> >
> > Suggested-by: Andrew Lunn <[email protected]>
> > Reviewed-by: Florian Fainelli <[email protected]>
> > Signed-off-by: Dejin Zheng <[email protected]>
> > ---
> > v6 -> v7:
> > - adapt to a newly added parameter sleep_before_read.
> > v5 -> v6:
> > - no changed.
> > v4 -> v5:
> > - add msleep before phy_read_poll_timeout() to keep the
> > code more similar
> > v3 -> v4:
> > - add this patch by Andrew's suggestion. Thanks Andrew!
> >
> > 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 & MII_LAN83C185_ENERGYON, 10000,
> > + 640000, true);
> > + if (rc < 0)
> > + return rc;
> >
> > /* Re-enable EDPD */
> > rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
> > --
> > 2.25.0
> >
>
> This patch causes the kernel log to be spammed with the following when
> Ethernet cable is not connected:
> SMSC LAN8710/LAN8720 2188000.ethernet-1:00: lan87xx_read_status failed: -110
>
Kevin, I am very sorry for the trouble caused by my patch.

> It still seems to work but I think that is only a fluke.
>
> The "if (rc < 0)" is not actually checking the return value of
> phy_read_poll_timeout but is looking at the value of the register read. I
> don't think rc will ever be negative in this case. If you change the code
> to "rc = phy_read_poll_timeout(...)" so that it actually checks the error
> then the function will behave differently than before. The original code
> would only return an error if phy_read returned an error. On a timeout it
> just continued. So the "if" could be changed to "if (rc < 0 && rc !=
> -ETIMEDOUT)". But you will still get the extra messages in the log that
> were not there before.
>
Yes, My patch did change the original behavior. It will not have error message
whether it is timeout or phy_read fails, but my patch changed it and will
print some error messages. It is my mistake. I'm so sorry for that.
How do you think of the following fix?

> > /* 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 & MII_LAN83C185_ENERGYON, 10000,
> > + 640000, true);
> > + if (rc < 0)
> > + return rc;

ret = read_poll_timeout(phy_read, rc, rc & MII_LAN83C185_ENERGYON || rc < 0,
10000, 640000, true, phydev, MII_LAN83C185_CTRL_STATUS);
if (!ret && rc < 0)
return rc;
BR,
Dejin
>
> Kevin