--- /dev/null
+From e96bd2d3b1f83170d1d5c1a99e439b39a22a5b58 Mon Sep 17 00:00:00 2001
+From: Petr Oros <poros@redhat.com>
+Date: Tue, 18 Feb 2020 10:35:55 +0100
+Subject: phy: avoid unnecessary link-up delay in polling mode
+
+From: Petr Oros <poros@redhat.com>
+
+commit e96bd2d3b1f83170d1d5c1a99e439b39a22a5b58 upstream.
+
+commit 93c0970493c71f ("net: phy: consider latched link-down status in
+polling mode") removed double-read of latched link-state register for
+polling mode from genphy_update_link(). This added extra ~1s delay into
+sequence link down->up.
+Following scenario:
+ - After boot link goes up
+ - phy_start() is called triggering an aneg restart, hence link goes
+ down and link-down info is latched.
+ - After aneg has finished link goes up. In phy_state_machine is checked
+ link state but it is latched "link is down". The state machine is
+ scheduled after one second and there is detected "link is up". This
+ extra delay can be avoided when we keep link-state register double read
+ in case when link was down previously.
+
+With this solution we don't miss a link-down event in polling mode and
+link-up is faster.
+
+Details about this quirky behavior on Realtek phy:
+Without patch:
+T0: aneg is started, link goes down, link-down status is latched
+T0+3s: state machine runs, up-to-date link-down is read
+T0+4s: state machine runs, aneg is finished (BMSR_ANEGCOMPLETE==1),
+ here i read link-down (BMSR_LSTATUS==0),
+T0+5s: state machine runs, aneg is finished (BMSR_ANEGCOMPLETE==1),
+ up-to-date link-up is read (BMSR_LSTATUS==1),
+ phydev->link goes up, state change PHY_NOLINK to PHY_RUNNING
+
+With patch:
+T0: aneg is started, link goes down, link-down status is latched
+T0+3s: state machine runs, up-to-date link-down is read
+T0+4s: state machine runs, aneg is finished (BMSR_ANEGCOMPLETE==1),
+ first BMSR read: BMSR_ANEGCOMPLETE==1 and BMSR_LSTATUS==0,
+ second BMSR read: BMSR_ANEGCOMPLETE==1 and BMSR_LSTATUS==1,
+ phydev->link goes up, state change PHY_NOLINK to PHY_RUNNING
+
+Signed-off-by: Petr Oros <poros@redhat.com>
+Reviewed-by: Heiner Kallweit <hkallweit1@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Cc: Macpaul Lin <macpaul.lin@mediatek.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/phy/phy-c45.c | 5 +++--
+ drivers/net/phy/phy_device.c | 5 +++--
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/phy-c45.c
++++ b/drivers/net/phy/phy-c45.c
+@@ -239,9 +239,10 @@ int genphy_c45_read_link(struct phy_devi
+
+ /* The link state is latched low so that momentary link
+ * drops can be detected. Do not double-read the status
+- * in polling mode to detect such short link drops.
++ * in polling mode to detect such short link drops except
++ * the link was already down.
+ */
+- if (!phy_polling_mode(phydev)) {
++ if (!phy_polling_mode(phydev) || !phydev->link) {
+ val = phy_read_mmd(phydev, devad, MDIO_STAT1);
+ if (val < 0)
+ return val;
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1766,9 +1766,10 @@ int genphy_update_link(struct phy_device
+
+ /* The link state is latched low so that momentary link
+ * drops can be detected. Do not double-read the status
+- * in polling mode to detect such short link drops.
++ * in polling mode to detect such short link drops except
++ * the link was already down.
+ */
+- if (!phy_polling_mode(phydev)) {
++ if (!phy_polling_mode(phydev) || !phydev->link) {
+ status = phy_read(phydev, MII_BMSR);
+ if (status < 0)
+ return status;