[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <E1a5zjK-000750-5O@rmk-PC.arm.linux.org.uk>
Date: Mon, 07 Dec 2015 17:37:42 +0000
From: Russell King <rmk+kernel@....linux.org.uk>
To: Florian Fainelli <f.fainelli@...il.com>,
Thomas Petazzoni <thomas.petazzoni@...e-electrons.com>
Cc: netdev@...r.kernel.org
Subject: [PATCH RFC 06/26] 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.
Signed-off-by: Russell King <rmk+kernel@....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(-)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index adb48abafc87..150497246922 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -802,6 +802,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
@@ -843,8 +853,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;
}
@@ -856,9 +865,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;
@@ -880,8 +887,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:
@@ -891,13 +897,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 or ignoring
@@ -920,14 +925,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);
@@ -935,8 +938,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;
@@ -956,11 +958,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;
@@ -972,11 +974,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 0bfbabad4431..67a654a1179b 100644
--- 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 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
@@ -659,6 +672,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 05fde31b6dc6..63e52af00493 100644
--- 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)
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists