summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2017-12-29 15:46:38 +0300
committerDavid S. Miller <davem@davemloft.net>2018-01-02 23:00:50 +0300
commit8c5e850c0ce597cf5934beba8b55f7651d2cd6da (patch)
treeb0c6bc880e95cbf7cf3a59466b18e6838cc687b3
parent36c4449a949c47ca152901758ee3c6175df35231 (diff)
downloadlinux-8c5e850c0ce597cf5934beba8b55f7651d2cd6da.tar.xz
net: phy: add helper to convert negotiation result to phy settings
Add a helper to convert the result of the autonegotiation advertisment into the PHYs speed and duplex settings. If the result is full duplex, also extract the pause mode settings from the link partner advertisment. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/phy/phy-core.c43
-rw-r--r--include/linux/phy.h2
2 files changed, 45 insertions, 0 deletions
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 21f75ae244b3..c0ad08fa9d2c 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -189,6 +189,49 @@ size_t phy_speeds(unsigned int *speeds, size_t size,
return count;
}
+/**
+ * phy_resolve_aneg_linkmode - resolve the advertisments into phy settings
+ * @phydev: The phy_device struct
+ *
+ * Resolve our and the link partner advertisments into their corresponding
+ * speed and duplex. If full duplex was negotiated, extract the pause mode
+ * from the link partner mask.
+ */
+void phy_resolve_aneg_linkmode(struct phy_device *phydev)
+{
+ u32 common = phydev->lp_advertising & phydev->advertising;
+
+ if (common & ADVERTISED_10000baseT_Full) {
+ phydev->speed = SPEED_10000;
+ phydev->duplex = DUPLEX_FULL;
+ } else if (common & ADVERTISED_1000baseT_Full) {
+ phydev->speed = SPEED_1000;
+ phydev->duplex = DUPLEX_FULL;
+ } else if (common & ADVERTISED_1000baseT_Half) {
+ phydev->speed = SPEED_1000;
+ phydev->duplex = DUPLEX_HALF;
+ } else if (common & ADVERTISED_100baseT_Full) {
+ phydev->speed = SPEED_100;
+ phydev->duplex = DUPLEX_FULL;
+ } else if (common & ADVERTISED_100baseT_Half) {
+ phydev->speed = SPEED_100;
+ phydev->duplex = DUPLEX_HALF;
+ } else if (common & ADVERTISED_10baseT_Full) {
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_FULL;
+ } else if (common & ADVERTISED_10baseT_Half) {
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_HALF;
+ }
+
+ if (phydev->duplex == DUPLEX_FULL) {
+ phydev->pause = !!(phydev->lp_advertising & ADVERTISED_Pause);
+ phydev->asym_pause = !!(phydev->lp_advertising &
+ ADVERTISED_Asym_Pause);
+ }
+}
+EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode);
+
static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
u16 regnum)
{
diff --git a/include/linux/phy.h b/include/linux/phy.h
index bc379a408c4f..a052e3768422 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -690,6 +690,8 @@ phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
size_t phy_speeds(unsigned int *speeds, size_t size,
unsigned long *mask, size_t maxbit);
+void phy_resolve_aneg_linkmode(struct phy_device *phydev);
+
/**
* phy_read_mmd - Convenience function for reading a register
* from an MMD on a given PHY.