diff options
Diffstat (limited to 'target/linux/mvebu/patches-4.4/125-phy-provide-a-hook-for-link-up-link-down-events.patch')
-rw-r--r-- | target/linux/mvebu/patches-4.4/125-phy-provide-a-hook-for-link-up-link-down-events.patch | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-4.4/125-phy-provide-a-hook-for-link-up-link-down-events.patch b/target/linux/mvebu/patches-4.4/125-phy-provide-a-hook-for-link-up-link-down-events.patch new file mode 100644 index 0000000000..b00968961f --- /dev/null +++ b/target/linux/mvebu/patches-4.4/125-phy-provide-a-hook-for-link-up-link-down-events.patch @@ -0,0 +1,183 @@ +From d8b4e728f598d3c8a9b219d4679d5de350caa082 Mon Sep 17 00:00:00 2001 +From: Russell King <rmk+kernel@arm.linux.org.uk> +Date: Fri, 18 Sep 2015 14:42:16 +0100 +Subject: [PATCH 714/744] 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> +--- + drivers/net/phy/phy.c | 42 ++++++++++++++++++++++-------------------- + drivers/net/phy/phy_device.c | 14 ++++++++++++++ + include/linux/phy.h | 1 + + 3 files changed, 37 insertions(+), 20 deletions(-) + +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -849,6 +849,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 +@@ -890,8 +900,7 @@ void phy_state_machine(struct work_struc + /* 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; + } + +@@ -903,9 +912,7 @@ void phy_state_machine(struct work_struc + /* 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; +@@ -930,8 +937,7 @@ void phy_state_machine(struct work_struc + } + } + phydev->state = PHY_RUNNING; +- netif_carrier_on(phydev->attached_dev); +- phydev->adjust_link(phydev->attached_dev); ++ phy_link_up(phydev); + } + break; + case PHY_FORCING: +@@ -941,13 +947,12 @@ void phy_state_machine(struct work_struc + + 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 or ignoring +@@ -970,14 +975,12 @@ void phy_state_machine(struct work_struc + + 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); +@@ -985,8 +988,7 @@ void phy_state_machine(struct work_struc + 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; +@@ -1006,11 +1008,11 @@ void phy_state_machine(struct work_struc + + 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; +@@ -1022,11 +1024,11 @@ void phy_state_machine(struct work_struc + + 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; + } +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -441,6 +441,19 @@ struct phy_device *phy_find_first(struct + } + 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 +@@ -659,6 +672,7 @@ int phy_attach_direct(struct net_device + goto error; + } + ++ phydev->phy_link_change = phy_link_change; + phydev->attached_dev = dev; + dev->phydev = phydev; + +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -433,6 +433,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(d, struct phy_device, dev) |