summaryrefslogtreecommitdiffstats
path: root/target/linux/mvebu/patches-4.4/125-phy-provide-a-hook-for-link-up-link-down-events.patch
diff options
context:
space:
mode:
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.patch183
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..17c1eadc16
--- /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
+@@ -847,6 +847,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
+@@ -888,8 +898,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;
+ }
+
+@@ -901,9 +910,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;
+@@ -928,8 +935,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:
+@@ -939,13 +945,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
+@@ -968,14 +973,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);
+@@ -983,8 +986,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;
+@@ -1004,11 +1006,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;
+@@ -1020,11 +1022,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)