Backport pending PCS standalone feature for kernel 6.12 and all the required dependency patch. All affected patch automatically refreshed. Link: https://github.com/openwrt/openwrt/pull/23271 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
149 lines
5.2 KiB
Diff
149 lines
5.2 KiB
Diff
From 96969b132bf1a5b875ab84fcb41a5c4972c3be9e Mon Sep 17 00:00:00 2001
|
|
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
|
Date: Mon, 19 Jan 2026 14:19:52 +0200
|
|
Subject: [PATCH 2/2] net: phylink: introduce helpers for replaying link
|
|
callbacks
|
|
|
|
Some drivers of MAC + tightly integrated PCS (example: SJA1105 + XPCS
|
|
covered by same reset domain) need to perform resets at runtime.
|
|
|
|
The reset is triggered by the MAC driver, and it needs to restore its
|
|
and the PCS' registers, all invisible to phylink.
|
|
|
|
However, there is a desire to simplify the API through which the MAC and
|
|
the PCS interact, so this becomes challenging.
|
|
|
|
Phylink holds all the necessary state to help with this operation, and
|
|
can offer two helpers which walk the MAC and PCS drivers again through
|
|
the callbacks required during a destructive reset operation. The
|
|
procedure is as follows:
|
|
|
|
Before reset, MAC driver calls phylink_replay_link_begin():
|
|
- Triggers phylink mac_link_down() and pcs_link_down() methods
|
|
|
|
After reset, MAC driver calls phylink_replay_link_end():
|
|
- Triggers phylink mac_config() -> pcs_config() -> mac_link_up() ->
|
|
pcs_link_up() methods.
|
|
|
|
MAC and PCS registers are restored with no other custom driver code.
|
|
|
|
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
|
Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
|
|
Link: https://patch.msgid.link/20260119121954.1624535-3-vladimir.oltean@nxp.com
|
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
---
|
|
drivers/net/phy/phylink.c | 61 +++++++++++++++++++++++++++++++++++++--
|
|
include/linux/phylink.h | 5 ++++
|
|
2 files changed, 63 insertions(+), 3 deletions(-)
|
|
|
|
--- a/drivers/net/phy/phylink.c
|
|
+++ b/drivers/net/phy/phylink.c
|
|
@@ -34,6 +34,7 @@ enum {
|
|
PHYLINK_DISABLE_STOPPED,
|
|
PHYLINK_DISABLE_LINK,
|
|
PHYLINK_DISABLE_MAC_WOL,
|
|
+ PHYLINK_DISABLE_REPLAY,
|
|
|
|
PCS_STATE_DOWN = 0,
|
|
PCS_STATE_STARTING,
|
|
@@ -83,6 +84,7 @@ struct phylink {
|
|
bool link_failed;
|
|
bool using_mac_select_pcs;
|
|
bool major_config_failed;
|
|
+ bool force_major_config;
|
|
|
|
struct sfp_bus *sfp_bus;
|
|
bool sfp_may_have_phy;
|
|
@@ -1768,9 +1770,10 @@ static void phylink_resolve(struct work_
|
|
if (pl->act_link_an_mode != MLO_AN_FIXED)
|
|
phylink_apply_manual_flow(pl, &link_state);
|
|
|
|
- if (mac_config && link_state.interface != pl->link_config.interface) {
|
|
- /* The interface has changed, so force the link down and then
|
|
- * reconfigure.
|
|
+ if ((mac_config && link_state.interface != pl->link_config.interface) ||
|
|
+ pl->force_major_config) {
|
|
+ /* The interface has changed or a forced major configuration
|
|
+ * was requested, so force the link down and then reconfigure.
|
|
*/
|
|
if (cur_link_state) {
|
|
phylink_link_down(pl);
|
|
@@ -1778,6 +1781,7 @@ static void phylink_resolve(struct work_
|
|
}
|
|
phylink_major_config(pl, false, &link_state);
|
|
pl->link_config.interface = link_state.interface;
|
|
+ pl->force_major_config = false;
|
|
}
|
|
|
|
/* If configuration of the interface failed, force the link down
|
|
@@ -4130,6 +4134,57 @@ void phylink_mii_c45_pcs_get_state(struc
|
|
}
|
|
EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state);
|
|
|
|
+/**
|
|
+ * phylink_replay_link_begin() - begin replay of link callbacks for driver
|
|
+ * which loses state
|
|
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
|
|
+ *
|
|
+ * Helper for MAC drivers which may perform a destructive reset at runtime.
|
|
+ * Both the own driver's mac_link_down() method is called, as well as the
|
|
+ * pcs_link_down() method of the split PCS (if any).
|
|
+ *
|
|
+ * This is similar to phylink_stop(), except it does not alter the state of
|
|
+ * the phylib PHY (it is assumed that it is not affected by the MAC destructive
|
|
+ * reset).
|
|
+ */
|
|
+void phylink_replay_link_begin(struct phylink *pl)
|
|
+{
|
|
+ ASSERT_RTNL();
|
|
+
|
|
+ phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_REPLAY);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(phylink_replay_link_begin);
|
|
+
|
|
+/**
|
|
+ * phylink_replay_link_end() - end replay of link callbacks for driver
|
|
+ * which lost state
|
|
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
|
|
+ *
|
|
+ * Helper for MAC drivers which may perform a destructive reset at runtime.
|
|
+ * Both the own driver's mac_config() and mac_link_up() methods, as well as the
|
|
+ * pcs_config() and pcs_link_up() method of the split PCS (if any), are called.
|
|
+ *
|
|
+ * This is similar to phylink_start(), except it does not alter the state of
|
|
+ * the phylib PHY.
|
|
+ *
|
|
+ * One must call this method only within the same rtnl_lock() critical section
|
|
+ * as a previous phylink_replay_link_start().
|
|
+ */
|
|
+void phylink_replay_link_end(struct phylink *pl)
|
|
+{
|
|
+ ASSERT_RTNL();
|
|
+
|
|
+ if (WARN(!test_bit(PHYLINK_DISABLE_REPLAY,
|
|
+ &pl->phylink_disable_state),
|
|
+ "phylink_replay_link_end() called without a prior phylink_replay_link_begin()\n"))
|
|
+ return;
|
|
+
|
|
+ pl->force_major_config = true;
|
|
+ phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_REPLAY);
|
|
+ flush_work(&pl->resolve);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(phylink_replay_link_end);
|
|
+
|
|
static int __init phylink_init(void)
|
|
{
|
|
for (int i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); ++i)
|
|
--- a/include/linux/phylink.h
|
|
+++ b/include/linux/phylink.h
|
|
@@ -707,4 +707,9 @@ void phylink_mii_c45_pcs_get_state(struc
|
|
|
|
void phylink_decode_usxgmii_word(struct phylink_link_state *state,
|
|
uint16_t lpa);
|
|
+
|
|
+void phylink_replay_link_begin(struct phylink *pl);
|
|
+
|
|
+void phylink_replay_link_end(struct phylink *pl);
|
|
+
|
|
#endif
|