[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20221118000124.2754581-6-vladimir.oltean@nxp.com>
Date: Fri, 18 Nov 2022 02:01:21 +0200
From: Vladimir Oltean <vladimir.oltean@....com>
To: netdev@...r.kernel.org
Cc: "David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>,
Heiner Kallweit <hkallweit1@...il.com>,
Andrew Lunn <andrew@...n.ch>,
Russell King <linux@...linux.org.uk>,
Florian Fainelli <f.fainelli@...il.com>,
UNGLinuxDriver@...rochip.com,
bcm-kernel-feedback-list@...adcom.com,
Madalin Bucur <madalin.bucur@....nxp.com>,
Camelia Groza <camelia.groza@....com>,
Claudiu Manoil <claudiu.manoil@....com>,
Ioana Ciornei <ioana.ciornei@....com>,
Maxim Kochetkov <fido_max@...ox.ru>,
Sean Anderson <sean.anderson@...o.com>,
Antoine Tenart <atenart@...nel.org>,
Michael Walle <michael@...le.cc>,
Raag Jadav <raagjadav@...il.com>,
Siddharth Vadapalli <s-vadapalli@...com>,
Ong Boon Leong <boon.leong.ong@...el.com>,
Colin Foster <colin.foster@...advantage.com>,
Marek Behun <marek.behun@....cz>
Subject: [PATCH v4 net-next 5/8] net: phylink: explicitly configure in-band autoneg for on-board PHYs
Currently Linux has no control over whether a MAC-to-PHY interface uses
in-band signaling or not, even though phylink has the
managed = "in-band-status";
property which denotes that the MAC expects in-band signaling to be used.
The problem is that if the in-band signaling is configurable in both the
PHY and the MAC, there is a risk that they are out of sync unless
phylink manages them both (setting in PHY may have come from out-of-reset
value, or from bootloader configuration). Most in-band autoneg state
machines follow IEEE 802.3 clause 37, which means that they will not
change the operating mode of the SERDES lane from control to data mode
unless in-band AN completed successfully. Therefore traffic will not
work.
To ensure that systems operate under full control of this particular
setting and not depend on what some other entity has done, let's
introduce a new PHY driver method for configuring in-band autoneg.
The first user will be phylink; the main PHY library does not call
phy_config_inband_autoneg(), because it does not know what to configure
it to. Presumably, individual non-phylink drivers can also call
phy_config_inband_autoneg() individually.
To avoid regressions with board device trees which may rely on fragile
mechanisms, gate the phy_config_inband_autoneg() call with the
bool sync_an_inband opt-in. Also skip doing it for PHYs on SFP modules.
I don't see a need for those, so don't risk making a change there.
Signed-off-by: Vladimir Oltean <vladimir.oltean@....com>
---
v3->v4:
- s/inband_aneg/an_inband/
- clearer comments, added kerneldocs
- opt-in via phylink_config :: sync_an_inband
drivers/net/phy/phy.c | 26 ++++++++++++++++++++++++++
drivers/net/phy/phylink.c | 12 ++++++++++++
include/linux/phy.h | 10 ++++++++++
3 files changed, 48 insertions(+)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 2abbacf2c7cb..37cdd9afd7e1 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -758,6 +758,32 @@ int phy_validate_an_inband(struct phy_device *phydev,
}
EXPORT_SYMBOL_GPL(phy_validate_an_inband);
+/**
+ * phy_config_an_inband - modify in-band autoneg setting
+ * @phydev: the phy_device struct
+ * @interface: the MAC-side interface type
+ * @enabled: selects whether in-band autoneg is used or not
+ *
+ * Configures the PHY to enable or disable in-band autoneg for the given
+ * interface type. @enabled can be passed as true only if the bit mask returned
+ * by @phy_validate_an_inband() contains @PHY_AN_INBAND_ON, and false only if
+ * it contains @PHY_AN_INBAND_OFF.
+ *
+ * Returns 0 on success, negative error otherwise.
+ */
+int phy_config_an_inband(struct phy_device *phydev, phy_interface_t interface,
+ bool enabled)
+{
+ if (!phydev->drv)
+ return -EIO;
+
+ if (!phydev->drv->config_an_inband)
+ return -EOPNOTSUPP;
+
+ return phydev->drv->config_an_inband(phydev, interface, enabled);
+}
+EXPORT_SYMBOL_GPL(phy_config_an_inband);
+
/**
* _phy_start_aneg - start auto-negotiation for this PHY device
* @phydev: the phy_device struct
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 598f5feb661e..ca3facc4f1a7 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1691,6 +1691,18 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
return ret;
}
+ if (pl->config->sync_an_inband && !phy_on_sfp(phy)) {
+ bool use_inband = phylink_autoneg_inband(pl->cur_link_an_mode);
+
+ ret = phy_config_an_inband(phy, interface, use_inband);
+ if (ret && ret != -EOPNOTSUPP) {
+ phylink_err(pl,
+ "failed to configure PHY in-band autoneg: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ }
+
phy->phylink = pl;
phy->phy_link_change = phylink_phy_change;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 56a431d88dd9..6f8d5765cf0c 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -860,6 +860,14 @@ struct phy_driver {
int (*validate_an_inband)(struct phy_device *phydev,
phy_interface_t interface);
+ /**
+ * @config_an_inband: Enable or disable in-band auto-negotiation for
+ * the system-side interface if the PHY operates in a mode that
+ * requires it: (Q)SGMII, USXGMII, 1000Base-X, etc.
+ */
+ int (*config_an_inband)(struct phy_device *phydev,
+ phy_interface_t interface, bool enabled);
+
/** @aneg_done: Determines the auto negotiation result */
int (*aneg_done)(struct phy_device *phydev);
@@ -1557,6 +1565,8 @@ int phy_start_aneg(struct phy_device *phydev);
int phy_aneg_done(struct phy_device *phydev);
int phy_validate_an_inband(struct phy_device *phydev,
phy_interface_t interface);
+int phy_config_an_inband(struct phy_device *phydev, phy_interface_t interface,
+ bool enabled);
int phy_speed_down(struct phy_device *phydev, bool sync);
int phy_speed_up(struct phy_device *phydev);
--
2.34.1
Powered by blists - more mailing lists