Skip to contentSkip to conversation

net: phy: improve and simplify phylib state machine

PATCH In review Heiner Kallweit 4 participants 15 messages Nov 8, 2018 – Nov 9, 2018

Subsystems (3)
lore
Share & tools
lore

Heiner Kallweit

author maintainer
#0 lore raw

cover net: phy: improve and simplify phylib state machine

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

- Info in clause 22/45 registers doesn't allow to differentiate between these two states:
1. Link is physically down
2. A link partner is connected and PHY is autonegotiating In both cases "link up" and "aneg finished" bits aren't set. One consequence is that having separate states PHY_NOLINK and PHY_AN isn't needed.

By using these two axioms the state machine can be significantly simplified.

Heiner Kallweit (5):
net: phy: remove useless check in state machine case PHY_NOLINK
net: phy: remove useless check in state machine case PHY_RESUMING
net: phy: add phy_check_link_status
net: phy: remove state PHY_AN
net: phy: use phy_check_link_status in more places in the state machine

 drivers/net/phy/phy.c | 172 +++++++++++-------------------------------
 include/linux/phy.h   |  19 +----
 2 files changed, 46 insertions(+), 145 deletions(-)
Signature · 1 line
2.19.1
author maintainer
#1 lore raw

PATCH 1/5 net: phy: remove useless check in state machine case PHY_NOLINK

If aneg is enabled and the PHY reports the link as up then definitely aneg finished successfully. Therefore this check is useless and can be removed.

---
 drivers/net/phy/phy.c | 11 -----------
 1 file changed, 11 deletions(-)
drivers/net/phy/phy.c +0 -11
index 476578746..87c6d304c 100644
@@ -970,17 +970,6 @@ void phy_state_machine(struct work_struct *work)
 			break;
 
 		if (phydev->link) {
-			if (AUTONEG_ENABLE == phydev->autoneg) {
-				err = phy_aneg_done(phydev);
-				if (err < 0)
-					break;
-
-				if (!err) {
-					phydev->state = PHY_AN;
-					phydev->link_timeout = PHY_AN_TIMEOUT;
-					break;
-				}
-			}
 			phydev->state = PHY_RUNNING;
 			phy_link_up(phydev);
 		}
Signature · 1 line
2.19.1
author maintainer
#2 lore raw

PATCH 2/5 net: phy: remove useless check in state machine case PHY_RESUMING

In reply to Heiner Kallweit

If aneg isn't finished yet then the PHY reports the link as down. There's no benefit in setting the state to PHY_AN because the next state machine run would set the status to PHY_NOLINK anyway (except in the meantime aneg has been finished and link is up). Therefore we can set the state to PHY_RUNNING or PHY_NOLINK directly.

In addition change the do_carrier parameter in phy_link_down() to true. If carrier was marked as up before (what should never be the case because PHY was in state PHY_HALTED before) then we should mark it as down now.

---
 drivers/net/phy/phy.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)
drivers/net/phy/phy.c +1 -12
index 87c6d304c..14dffa0da 100644
@@ -1022,17 +1022,6 @@ void phy_state_machine(struct work_struct *work)
 		}
 		break;
 	case PHY_RESUMING:
-		if (AUTONEG_ENABLE == phydev->autoneg) {
-			err = phy_aneg_done(phydev);
-			if (err < 0) {
-				break;
-			} else if (!err) {
-				phydev->state = PHY_AN;
-				phydev->link_timeout = PHY_AN_TIMEOUT;
-				break;
-			}
-		}
-
 		err = phy_read_status(phydev);
 		if (err)
 			break;
@@ -1042,7 +1031,7 @@ void phy_state_machine(struct work_struct *work)
 			phy_link_up(phydev);
 		} else	{
 			phydev->state = PHY_NOLINK;
-			phy_link_down(phydev, false);
+			phy_link_down(phydev, true);
 		}
 		break;
 	}
Signature · 1 line
2.19.1
author maintainer
#3 lore raw

PATCH 3/5 net: phy: add phy_check_link_status

In reply to Heiner Kallweit

In few places in the state machine the state is set to PHY_RUNNING or PHY_NOLINK after doing a phy_read_status(). So factor this out to phy_check_link_status().

First use it in phy_start_aneg(): By setting the state to PHY_RUNNING or PHY_NOLINK directly we can remove the code to handle the case that we're using interrupts and aneg was finished already.

Definition of phy_link_up and phy_link_down needs to be moved because they are called in the new function.

---
 drivers/net/phy/phy.c | 70 ++++++++++++++++++++++++-------------------
 1 file changed, 40 insertions(+), 30 deletions(-)
drivers/net/phy/phy.c +40 -30
index 14dffa0da..87ed00030 100644
@@ -62,6 +62,17 @@ static const char *phy_state_to_str(enum phy_state st)
 	return NULL;
 }
 
+static void phy_link_up(struct phy_device *phydev)
+{
+	phydev->phy_link_change(phydev, true, true);
+	phy_led_trigger_change_speed(phydev);
+}
+
+static void phy_link_down(struct phy_device *phydev, bool do_carrier)
+{
+	phydev->phy_link_change(phydev, false, do_carrier);
+	phy_led_trigger_change_speed(phydev);
+}
 
 /**
  * phy_print_status - Convenience function to print out the current phy status
@@ -493,6 +504,34 @@ static int phy_config_aneg(struct phy_device *phydev)
 	return genphy_config_aneg(phydev);
 }
 
+/**
+ * phy_check_link_status - check link status and set state accordingly
+ * @phydev: the phy_device struct
+ *
+ * Description: Check for link and whether autoneg was triggered / is running
+ * and set state accordingly
+ */
+static int phy_check_link_status(struct phy_device *phydev)
+{
+	int err;
+
+	WARN_ON(!mutex_is_locked(&phydev->lock));
+
+	err = phy_read_status(phydev);
+	if (err)
+		return err;
+
+	if (phydev->link && phydev->state != PHY_RUNNING) {
+		phydev->state = PHY_RUNNING;
+		phy_link_up(phydev);
+	} else if (!phydev->link && phydev->state != PHY_NOLINK) {
+		phydev->state = PHY_NOLINK;
+		phy_link_down(phydev, true);
+	}
+
+	return 0;
+}
+
 /**
  * phy_start_aneg - start auto-negotiation for this PHY device
  * @phydev: the phy_device struct
@@ -504,7 +543,6 @@ static int phy_config_aneg(struct phy_device *phydev)
  */
 int phy_start_aneg(struct phy_device *phydev)
 {
-	bool trigger = 0;
 	int err;
 
 	if (!phydev->drv)
@@ -524,32 +562,16 @@ int phy_start_aneg(struct phy_device *phydev)
 
 	if (phydev->state != PHY_HALTED) {
 		if (AUTONEG_ENABLE == phydev->autoneg) {
-			phydev->state = PHY_AN;
-			phydev->link_timeout = PHY_AN_TIMEOUT;
+			err = phy_check_link_status(phydev);
 		} else {
 			phydev->state = PHY_FORCING;
 			phydev->link_timeout = PHY_FORCE_TIMEOUT;
 		}
 	}
 
-	/* Re-schedule a PHY state machine to check PHY status because
-	 * negotiation may already be done and aneg interrupt may not be
-	 * generated.
-	 */
-	if (!phy_polling_mode(phydev) && phydev->state == PHY_AN) {
-		err = phy_aneg_done(phydev);
-		if (err > 0) {
-			trigger = true;
-			err = 0;
-		}
-	}
-
 out_unlock:
 	mutex_unlock(&phydev->lock);
 
-	if (trigger)
-		phy_trigger_machine(phydev);
-
 	return err;
 }
 EXPORT_SYMBOL(phy_start_aneg);
@@ -893,18 +915,6 @@ void phy_start(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_start);
 
-static void phy_link_up(struct phy_device *phydev)
-{
-	phydev->phy_link_change(phydev, true, true);
-	phy_led_trigger_change_speed(phydev);
-}
-
-static void phy_link_down(struct phy_device *phydev, bool do_carrier)
-{
-	phydev->phy_link_change(phydev, false, do_carrier);
-	phy_led_trigger_change_speed(phydev);
-}
-
 /**
  * phy_state_machine - Handle the state machine
  * @work: work_struct that describes the work to be done
Signature · 1 line
2.19.1
author maintainer
#4 lore raw

PATCH 4/5 net: phy: remove state PHY_AN

In reply to Heiner Kallweit

After the recent changes in the state machine state PHY_AN isn't used any longer and can be removed.

---
 drivers/net/phy/phy.c | 27 ---------------------------
 include/linux/phy.h   | 19 +------------------
 2 files changed, 1 insertion(+), 45 deletions(-)
drivers/net/phy/phy.c +0 -27
index 87ed00030..226824804 100644
@@ -50,7 +50,6 @@ static const char *phy_state_to_str(enum phy_state st)
 	PHY_STATE_STR(READY)
 	PHY_STATE_STR(PENDING)
 	PHY_STATE_STR(UP)
-	PHY_STATE_STR(AN)
 	PHY_STATE_STR(RUNNING)
 	PHY_STATE_STR(NOLINK)
 	PHY_STATE_STR(FORCING)
@@ -944,32 +943,6 @@ void phy_state_machine(struct work_struct *work)
 	case PHY_UP:
 		needs_aneg = true;
 
-		phydev->link_timeout = PHY_AN_TIMEOUT;
-
-		break;
-	case PHY_AN:
-		err = phy_read_status(phydev);
-		if (err < 0)
-			break;
-
-		/* If the link is down, give up on negotiation for now */
-		if (!phydev->link) {
-			phydev->state = PHY_NOLINK;
-			phy_link_down(phydev, true);
-			break;
-		}
-
-		/* Check if negotiation is done.  Break if there's an error */
-		err = phy_aneg_done(phydev);
-		if (err < 0)
-			break;
-
-		/* If AN is done, we're running */
-		if (err > 0) {
-			phydev->state = PHY_RUNNING;
-			phy_link_up(phydev);
-		} else if (0 == phydev->link_timeout--)
-			needs_aneg = true;
 		break;
 	case PHY_NOLINK:
 		if (!phy_polling_mode(phydev))
include/linux/phy.h +1 -18
index 9e4d49ef4..2090277ea 100644
@@ -178,7 +178,6 @@ static inline const char *phy_modes(phy_interface_t interface)
 #define PHY_INIT_TIMEOUT	100000
 #define PHY_STATE_TIME		1
 #define PHY_FORCE_TIMEOUT	10
-#define PHY_AN_TIMEOUT		10
 
 #define PHY_MAX_ADDR	32
 
@@ -297,24 +296,10 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr);
  *
  * UP: The PHY and attached device are ready to do work.
  * Interrupts should be started here.
- * - timer moves to AN
- *
- * AN: The PHY is currently negotiating the link state.  Link is
- * therefore down for now.  phy_timer will set this state when it
- * detects the state is UP.  config_aneg will set this state
- * whenever called with phydev->autoneg set to AUTONEG_ENABLE.
- * - If autonegotiation finishes, but there's no link, it sets
- *   the state to NOLINK.
- * - If aneg finishes with link, it sets the state to RUNNING,
- *   and calls adjust_link
- * - If autonegotiation did not finish after an arbitrary amount
- *   of time, autonegotiation should be tried again if the PHY
- *   supports "magic" autonegotiation (back to AN)
- * - If it didn't finish, and no magic_aneg, move to FORCING.
+ * - timer moves to NOLINK or RUNNING
  *
  * NOLINK: PHY is up, but not currently plugged in.
  * - If the timer notes that the link comes back, we move to RUNNING
- * - config_aneg moves to AN
  * - phy_stop moves to HALTED
  *
  * FORCING: PHY is being configured with forced settings
@@ -329,7 +314,6 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr);
  *   link state is polled every other cycle of this state machine,
  *   which makes it every other second)
  * - irq will set CHANGELINK
- * - config_aneg will set AN
  * - phy_stop moves to HALTED
  *
  * CHANGELINK: PHY experienced a change in link state
@@ -353,7 +337,6 @@ enum phy_state {
 	PHY_READY,
 	PHY_PENDING,
 	PHY_UP,
-	PHY_AN,
 	PHY_RUNNING,
 	PHY_NOLINK,
 	PHY_FORCING,
Signature · 1 line
2.19.1
author maintainer
#5 lore raw

PATCH 5/5 net: phy: use phy_check_link_status in more places in the state machine

In reply to Heiner Kallweit

Use phy_check_link_status in more places in the state machine.

---
 drivers/net/phy/phy.c | 53 ++++---------------------------------------
 1 file changed, 5 insertions(+), 48 deletions(-)
drivers/net/phy/phy.c +5 -48
index 226824804..dd5bff955 100644
@@ -945,17 +945,13 @@ void phy_state_machine(struct work_struct *work)
 
 		break;
 	case PHY_NOLINK:
+	case PHY_RUNNING:
 		if (!phy_polling_mode(phydev))
 			break;
-
-		err = phy_read_status(phydev);
-		if (err)
-			break;
-
-		if (phydev->link) {
-			phydev->state = PHY_RUNNING;
-			phy_link_up(phydev);
-		}
+		/* fall through */
+	case PHY_CHANGELINK:
+	case PHY_RESUMING:
+		err = phy_check_link_status(phydev);
 		break;
 	case PHY_FORCING:
 		err = genphy_update_link(phydev);
@@ -971,32 +967,6 @@ void phy_state_machine(struct work_struct *work)
 			phy_link_down(phydev, false);
 		}
 		break;
-	case PHY_RUNNING:
-		if (!phy_polling_mode(phydev))
-			break;
-
-		err = phy_read_status(phydev);
-		if (err)
-			break;
-
-		if (!phydev->link) {
-			phydev->state = PHY_NOLINK;
-			phy_link_down(phydev, true);
-		}
-		break;
-	case PHY_CHANGELINK:
-		err = phy_read_status(phydev);
-		if (err)
-			break;
-
-		if (phydev->link) {
-			phydev->state = PHY_RUNNING;
-			phy_link_up(phydev);
-		} else {
-			phydev->state = PHY_NOLINK;
-			phy_link_down(phydev, true);
-		}
-		break;
 	case PHY_HALTED:
 		if (phydev->link) {
 			phydev->link = 0;
@@ -1004,19 +974,6 @@ void phy_state_machine(struct work_struct *work)
 			do_suspend = true;
 		}
 		break;
-	case PHY_RESUMING:
-		err = phy_read_status(phydev);
-		if (err)
-			break;
-
-		if (phydev->link) {
-			phydev->state = PHY_RUNNING;
-			phy_link_up(phydev);
-		} else	{
-			phydev->state = PHY_NOLINK;
-			phy_link_down(phydev, true);
-		}
-		break;
 	}
 
 	mutex_unlock(&phydev->lock);
Signature · 1 line
2.19.1
maintainer
#6 lore raw
In reply to Heiner Kallweit
Quoted 3 lines · Heiner Kallweit

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

Hi Heiner

I think that is a risky assumption to make.

What happens if this assumption is incorrect?

Andrew

author maintainer
#7 lore raw
Quoted 9 lines · Andrew Lunn
Quoted 3 lines · Heiner Kallweit

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

Hi Heiner

I think that is a risky assumption to make.

I wasn't sure initially too (found no clear rule in 802.3 clause 22) and therefore asked around. Florian agrees to the assumption, see here: https://www.spinics.net/lists/netdev/msg519242.html

If a PHY reports the link as up then every user would assume that data can be transferred. But that's not the case during aneg. Therefore reporting the link as up during aneg wouldn't make sense.

Quoted 2 lines

What happens if this assumption is incorrect?

Then we have to flush this patch series down the drain ;) At least I would have to check in detail which parts need to be changed. I clearly mention the assumptions so that every reviewer can check whether he agrees.

Quoted 2 lines

Andrew

Heiner

maintainer
#8 lore raw
Quoted 10 lines · Heiner Kallweit
Quoted 9 lines · Andrew Lunn
Quoted 3 lines · Heiner Kallweit

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

Hi Heiner

I think that is a risky assumption to make.

Quoted 7 lines

I wasn't sure initially too (found no clear rule in 802.3 clause 22) and therefore asked around. Florian agrees to the assumption, see here: https://www.spinics.net/lists/netdev/msg519242.html

If a PHY reports the link as up then every user would assume that data can be transferred. But that's not the case during aneg. Therefore reporting the link as up during aneg wouldn't make sense.

Hi Heiner

If auto-neg has already been completed once before, i can see a lazy hardware designed not reporting link down, or at least, not until auto-neg actually fails.

And what about if link is down for too short a time for us to notice? I've seen some code fail because the kernel went off and did something else for too long, and a state change was missed.

Quoted 6 lines
Quoted 2 lines

What happens if this assumption is incorrect?

Then we have to flush this patch series down the drain ;) At least I would have to check in detail which parts need to be changed. I clearly mention the assumptions so that every reviewer can check whether he agrees.

Thanks for doing that. I want to be happy this is safe, and not going to introduce regressions.

Andrew

author maintainer
#9 lore raw
Quoted 19 lines · Andrew Lunn
Quoted 10 lines · Heiner Kallweit
Quoted 9 lines · Andrew Lunn
Quoted 3 lines · Heiner Kallweit

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

Hi Heiner

I think that is a risky assumption to make.

Quoted 7 lines

I wasn't sure initially too (found no clear rule in 802.3 clause 22) and therefore asked around. Florian agrees to the assumption, see here: https://www.spinics.net/lists/netdev/msg519242.html

If a PHY reports the link as up then every user would assume that data can be transferred. But that's not the case during aneg. Therefore reporting the link as up during aneg wouldn't make sense.

Quoted 6 lines

Hi Heiner

If auto-neg has already been completed once before, i can see a lazy hardware designed not reporting link down, or at least, not until auto-neg actually fails.

"aneg finished" flag means that the aneg parameters in the register set are valid. Once the link goes down that's not necessarily the case any longer. E.g. some PHYs have an "auto speed down" feature and reduce the speed to save power once they detect the link is down. Of course I can not rule out that there are broken designs (or as you stated more politely: lazy designs) out there. But in this case I assume we would see issues already. And we would have to think about whether we want to support such broken / lazy designs in phylib.

Quoted 4 lines

And what about if link is down for too short a time for us to notice? I've seen some code fail because the kernel went off and did something else for too long, and a state change was missed.

This is a case we have already, independent of my change. genphy_update_link() reads BMSR twice, thus ignoring potential latched info about a temporary link failure. When polling phylib ignores everything that happens between two poll intervals.

Quoted 12 lines
Quoted 6 lines
Quoted 2 lines

What happens if this assumption is incorrect?

Then we have to flush this patch series down the drain ;) At least I would have to check in detail which parts need to be changed. I clearly mention the assumptions so that every reviewer can check whether he agrees.

Thanks for doing that. I want to be happy this is safe, and not going to introduce regressions.

Andrew

author maintainer
#10 lore raw
Quoted 26 lines · Heiner Kallweit
Quoted 19 lines · Andrew Lunn
Quoted 10 lines · Heiner Kallweit
Quoted 9 lines · Andrew Lunn
Quoted 3 lines · Heiner Kallweit

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

Hi Heiner

I think that is a risky assumption to make.

Quoted 7 lines

I wasn't sure initially too (found no clear rule in 802.3 clause 22) and therefore asked around. Florian agrees to the assumption, see here: https://www.spinics.net/lists/netdev/msg519242.html

If a PHY reports the link as up then every user would assume that data can be transferred. But that's not the case during aneg. Therefore reporting the link as up during aneg wouldn't make sense.

Quoted 6 lines

Hi Heiner

If auto-neg has already been completed once before, i can see a lazy hardware designed not reporting link down, or at least, not until auto-neg actually fails.

Quoted 9 lines

"aneg finished" flag means that the aneg parameters in the register set are valid. Once the link goes down that's not necessarily the case any longer. E.g. some PHYs have an "auto speed down" feature and reduce the speed to save power once they detect the link is down. Of course I can not rule out that there are broken designs (or as you stated more politely: lazy designs) out there. But in this case I assume we would see issues already. And we would have to think about whether we want to support such broken / lazy designs in phylib.

Had one more look at the changes to check what happens if "link up" and "aneg done" are not in sync.

When link goes down the changes don't change current behavior. We just check the "link up" bit.

When link goes up and aneg isn't finished yet, then we would report "link is up" earlier to userspace than we do now. If userspace starts some network activity based on the "link up" event then they may fail. But it really would be a major flaw if a PHY signals "link up" whilst it's not actually ready yet to transfer data.

In case of such a broken design we would have issues with the current code already, at least if interrupts are used. The "link up" interrupt would cause the state machine to go to PHY_CHANGELINK which doesn't check for aneg status.

Quoted 22 lines
Quoted 4 lines

And what about if link is down for too short a time for us to notice? I've seen some code fail because the kernel went off and did something else for too long, and a state change was missed.

This is a case we have already, independent of my change. genphy_update_link() reads BMSR twice, thus ignoring potential latched info about a temporary link failure. When polling phylib ignores everything that happens between two poll intervals.

Quoted 12 lines
Quoted 6 lines
Quoted 2 lines

What happens if this assumption is incorrect?

Then we have to flush this patch series down the drain ;) At least I would have to check in detail which parts need to be changed. I clearly mention the assumptions so that every reviewer can check whether he agrees.

Thanks for doing that. I want to be happy this is safe, and not going to introduce regressions.

Andrew

maintainer
#11 lore raw
In reply to Heiner Kallweit

From: Heiner Kallweit <[email protected]>
Date: Wed, 7 Nov 2018 20:41:52 +0100

Quoted 12 lines

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

- Info in clause 22/45 registers doesn't allow to differentiate between these two states:
1. Link is physically down
2. A link partner is connected and PHY is autonegotiating In both cases "link up" and "aneg finished" bits aren't set. One consequence is that having separate states PHY_NOLINK and PHY_AN isn't needed.

Quoted 2 lines

By using these two axioms the state machine can be significantly simplified.

So how are we going to move forward on this?

Maybe we can apply this series and just watch carefully for any problems that get reported or are found?

#12 lore raw
Quoted 15 lines · David Miller

From: Heiner Kallweit <[email protected]>
Date: Wed, 7 Nov 2018 20:41:52 +0100

Quoted 12 lines

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

- Info in clause 22/45 registers doesn't allow to differentiate between these two states:
1. Link is physically down
2. A link partner is connected and PHY is autonegotiating In both cases "link up" and "aneg finished" bits aren't set. One consequence is that having separate states PHY_NOLINK and PHY_AN isn't needed.

Quoted 7 lines
Quoted 2 lines

By using these two axioms the state machine can be significantly simplified.

So how are we going to move forward on this?

Maybe we can apply this series and just watch carefully for any problems that get reported or are found?

Given Heiner is always responsive and taking care of fixing what might be/have broken, no objections with me on that.

Signature · 1 line
Florian
maintainer
#13 lore raw
Quoted 19 lines · Florian Fainelli
Quoted 18 lines · David Miller

From: Heiner Kallweit <[email protected]>
Date: Wed, 7 Nov 2018 20:41:52 +0100

Quoted 14 lines

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

- Info in clause 22/45 registers doesn't allow to differentiate between these two states:
1. Link is physically down
2. A link partner is connected and PHY is autonegotiating In both cases "link up" and "aneg finished" bits aren't set. One consequence is that having separate states PHY_NOLINK and PHY_AN isn't needed.

By using these two axioms the state machine can be significantly simplified.

Quoted 7 lines
Quoted 4 lines

So how are we going to move forward on this?

Maybe we can apply this series and just watch carefully for any problems that get reported or are found?

Given Heiner is always responsive and taking care of fixing what might be/have broken, no objections with me on that.

Yes, lets try it.

Andrew

maintainer
#14 lore raw
In reply to Florian Fainelli

From: Florian Fainelli <[email protected]>
Date: Thu, 8 Nov 2018 15:00:01 -0800

Quoted 19 lines · David Miller
Quoted 18 lines

From: Heiner Kallweit <[email protected]>
Date: Wed, 7 Nov 2018 20:41:52 +0100

Quoted 14 lines

This patch series is based on two axioms:

- During autoneg a PHY always reports the link being down

- Info in clause 22/45 registers doesn't allow to differentiate between these two states:
1. Link is physically down
2. A link partner is connected and PHY is autonegotiating In both cases "link up" and "aneg finished" bits aren't set. One consequence is that having separate states PHY_NOLINK and PHY_AN isn't needed.

By using these two axioms the state machine can be significantly simplified.

Quoted 7 lines
Quoted 4 lines

So how are we going to move forward on this?

Maybe we can apply this series and just watch carefully for any problems that get reported or are found?

Given Heiner is always responsive and taking care of fixing what might be/have broken, no objections with me on that.

Great, I've applied this series to net-next then.

Thanks.