net: phylink: add support for PCS link change notifications
authorRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Thu, 13 Jul 2023 08:42:17 +0000 (09:42 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 14 Jul 2023 07:51:48 +0000 (08:51 +0100)
Add a function, phylink_pcs_change() which can be used by PCs drivers
to notify phylink about changes to the PCS link state.

Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/phylink.c
include/linux/phylink.h

index 9840a29..71b1012 100644 (file)
@@ -1137,6 +1137,11 @@ static void phylink_major_config(struct phylink *pl, bool restart,
        if (pcs_changed) {
                phylink_pcs_disable(pl->pcs);
 
+               if (pl->pcs)
+                       pl->pcs->phylink = NULL;
+
+               pcs->phylink = pl;
+
                pl->pcs = pcs;
        }
 
@@ -1991,6 +1996,14 @@ void phylink_disconnect_phy(struct phylink *pl)
 }
 EXPORT_SYMBOL_GPL(phylink_disconnect_phy);
 
+static void phylink_link_changed(struct phylink *pl, bool up, const char *what)
+{
+       if (!up)
+               pl->mac_link_dropped = true;
+       phylink_run_resolve(pl);
+       phylink_dbg(pl, "%s link %s\n", what, up ? "up" : "down");
+}
+
 /**
  * phylink_mac_change() - notify phylink of a change in MAC state
  * @pl: a pointer to a &struct phylink returned from phylink_create()
@@ -2001,13 +2014,30 @@ EXPORT_SYMBOL_GPL(phylink_disconnect_phy);
  */
 void phylink_mac_change(struct phylink *pl, bool up)
 {
-       if (!up)
-               pl->mac_link_dropped = true;
-       phylink_run_resolve(pl);
-       phylink_dbg(pl, "mac link %s\n", up ? "up" : "down");
+       phylink_link_changed(pl, up, "mac");
 }
 EXPORT_SYMBOL_GPL(phylink_mac_change);
 
+/**
+ * phylink_pcs_change() - notify phylink of a change to PCS link state
+ * @pcs: pointer to &struct phylink_pcs
+ * @up: indicates whether the link is currently up.
+ *
+ * The PCS driver should call this when the state of its link changes
+ * (e.g. link failure, new negotiation results, etc.) Note: it should
+ * not determine "up" by reading the BMSR. If in doubt about the link
+ * state at interrupt time, then pass true if pcs_get_state() returns
+ * the latched link-down state, otherwise pass false.
+ */
+void phylink_pcs_change(struct phylink_pcs *pcs, bool up)
+{
+       struct phylink *pl = pcs->phylink;
+
+       if (pl)
+               phylink_link_changed(pl, up, "pcs");
+}
+EXPORT_SYMBOL_GPL(phylink_pcs_change);
+
 static irqreturn_t phylink_link_handler(int irq, void *data)
 {
        struct phylink *pl = data;
index 99fc2fa..b28aa3e 100644 (file)
@@ -9,6 +9,7 @@ struct device_node;
 struct ethtool_cmd;
 struct fwnode_handle;
 struct net_device;
+struct phylink;
 
 enum {
        MLO_PAUSE_NONE,
@@ -520,14 +521,19 @@ struct phylink_pcs_ops;
 /**
  * struct phylink_pcs - PHYLINK PCS instance
  * @ops: a pointer to the &struct phylink_pcs_ops structure
+ * @phylink: pointer to &struct phylink_config
  * @neg_mode: provide PCS neg mode via "mode" argument
  * @poll: poll the PCS for link changes
  *
  * This structure is designed to be embedded within the PCS private data,
  * and will be passed between phylink and the PCS.
+ *
+ * The @phylink member is private to phylink and must not be touched by
+ * the PCS driver.
  */
 struct phylink_pcs {
        const struct phylink_pcs_ops *ops;
+       struct phylink *phylink;
        bool neg_mode;
        bool poll;
 };
@@ -699,6 +705,7 @@ int phylink_fwnode_phy_connect(struct phylink *pl,
 void phylink_disconnect_phy(struct phylink *);
 
 void phylink_mac_change(struct phylink *, bool up);
+void phylink_pcs_change(struct phylink_pcs *, bool up);
 
 void phylink_start(struct phylink *);
 void phylink_stop(struct phylink *);