diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-09-18 14:42:16 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2017-01-05 22:38:21 +0000 |
commit | 9935692bf0976149da724c69da63141f6894f669 (patch) | |
tree | debed28f49f647d8746d28c2eb1f1e6387de9f20 | |
parent | 6f7b4c2af983d61315b623ced4e6a9663cdd137a (diff) |
phy: provide a hook for link up/link down events
Sometimes, we need to do additional work between the PHY coming up and
marking the carrier present - for example, we may need to wait for the
PHY to MAC link to finish negotiation. This changes phylib to provide
a notification function pointer which avoids the built-in
netif_carrier_on() and netif_carrier_off() functions.
Standard ->adjust_link functionality is provided by hooking a helper
into the new ->phy_link_change method.
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | drivers/net/phy/phy.c | 42 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 14 | ||||
-rw-r--r-- | include/linux/phy.h | 1 |
3 files changed, 37 insertions, 20 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index feac3fb07f8c..94b79f7dea74 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -804,6 +804,16 @@ 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); +} + +static void phy_link_down(struct phy_device *phydev, bool do_carrier) +{ + phydev->phy_link_change(phydev, false, do_carrier); +} + /** * phy_state_machine - Handle the state machine * @work: work_struct that describes the work to be done @@ -845,8 +855,7 @@ void phy_state_machine(struct work_struct *work) /* If the link is down, give up on negotiation for now */ if (!phydev->link) { phydev->state = PHY_NOLINK; - netif_carrier_off(phydev->attached_dev); - phydev->adjust_link(phydev->attached_dev); + phy_link_down(phydev, true); break; } @@ -858,9 +867,7 @@ void phy_state_machine(struct work_struct *work) /* If AN is done, we're running */ if (err > 0) { phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); - phydev->adjust_link(phydev->attached_dev); - + phy_link_up(phydev); } else if (0 == phydev->link_timeout--) needs_aneg = true; break; @@ -885,8 +892,7 @@ void phy_state_machine(struct work_struct *work) } } phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); - phydev->adjust_link(phydev->attached_dev); + phy_link_up(phydev); } break; case PHY_FORCING: @@ -896,13 +902,12 @@ void phy_state_machine(struct work_struct *work) if (phydev->link) { phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); + phy_link_up(phydev); } else { if (0 == phydev->link_timeout--) needs_aneg = true; + phy_link_down(phydev, false); } - - phydev->adjust_link(phydev->attached_dev); break; case PHY_RUNNING: /* Only register a CHANGE if we are polling and link changed @@ -925,14 +930,12 @@ void phy_state_machine(struct work_struct *work) if (phydev->link) { phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); + phy_link_up(phydev); } else { phydev->state = PHY_NOLINK; - netif_carrier_off(phydev->attached_dev); + phy_link_down(phydev, true); } - phydev->adjust_link(phydev->attached_dev); - if (phy_interrupt_is_valid(phydev)) err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); @@ -940,8 +943,7 @@ void phy_state_machine(struct work_struct *work) case PHY_HALTED: if (phydev->link) { phydev->link = 0; - netif_carrier_off(phydev->attached_dev); - phydev->adjust_link(phydev->attached_dev); + phy_link_down(phydev, true); do_suspend = true; } break; @@ -961,11 +963,11 @@ void phy_state_machine(struct work_struct *work) if (phydev->link) { phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); + phy_link_up(phydev); } else { phydev->state = PHY_NOLINK; + phy_link_down(phydev, false); } - phydev->adjust_link(phydev->attached_dev); } else { phydev->state = PHY_AN; phydev->link_timeout = PHY_AN_TIMEOUT; @@ -977,11 +979,11 @@ void phy_state_machine(struct work_struct *work) if (phydev->link) { phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); + phy_link_up(phydev); } else { phydev->state = PHY_NOLINK; + phy_link_down(phydev, false); } - phydev->adjust_link(phydev->attached_dev); } break; } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 443f48a6f369..78da1cf82fc5 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -645,6 +645,19 @@ struct phy_device *phy_find_first(struct mii_bus *bus) } EXPORT_SYMBOL(phy_find_first); +static void phy_link_change(struct phy_device *phydev, bool up, bool do_carrier) +{ + struct net_device *netdev = phydev->attached_dev; + + if (do_carrier) { + if (up) + netif_carrier_on(netdev); + else + netif_carrier_off(netdev); + } + phydev->adjust_link(netdev); +} + /** * phy_prepare_link - prepares the PHY layer to monitor link status * @phydev: target phy_device struct @@ -899,6 +912,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, goto error; } + phydev->phy_link_change = phy_link_change; phydev->attached_dev = dev; dev->phydev = phydev; diff --git a/include/linux/phy.h b/include/linux/phy.h index c1f05edcdf55..987515d3dc0d 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -426,6 +426,7 @@ struct phy_device { u8 mdix; + void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier); void (*adjust_link)(struct net_device *dev); }; #define to_phy_device(d) container_of(to_mdio_device(d), \ |