forked from Openwrt/openwrt
6c118efc01
Changelog: https://cdn.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.15.140 Removed upstreamed: mvebu/patches-5.15/106-Revert-i2c-pxa-move-to-generic-GPIO-recovery.patch[1] All other patches automatically rebased. 1. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.15.140&id=06d320ca170b4e59bb261e2ce3ffe84e9154d42b Build system: x86_64 Build-tested: ramips/tplink_archer-a6-v3 Run-tested: ramips/tplink_archer-a6-v3 Signed-off-by: John Audia <therealgraysky@proton.me>
198 lines
6.9 KiB
Diff
198 lines
6.9 KiB
Diff
From d1e86325af377129adb7fc6f34eb044ca6068b47 Mon Sep 17 00:00:00 2001
|
|
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
|
|
Date: Wed, 15 Dec 2021 15:34:15 +0000
|
|
Subject: [PATCH] net: phylink: add mac_select_pcs() method to phylink_mac_ops
|
|
|
|
mac_select_pcs() allows us to have an explicit point to query which
|
|
PCS the MAC wishes to use for a particular PHY interface mode, thereby
|
|
allowing us to add support to validate the link settings with the PCS.
|
|
|
|
Phylink will also use this to select the PCS to be used during a major
|
|
configuration event without the MAC driver needing to call
|
|
phylink_set_pcs().
|
|
|
|
Note that if mac_select_pcs() is present, the supported_interfaces
|
|
bitmap must be filled in; this avoids mac_select_pcs() being called
|
|
with PHY_INTERFACE_MODE_NA when we want to get support for all
|
|
interface types. Phylink will return an error in phylink_create()
|
|
unless this condition is satisfied.
|
|
|
|
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 | 68 +++++++++++++++++++++++++++++++++------
|
|
include/linux/phylink.h | 18 +++++++++++
|
|
2 files changed, 77 insertions(+), 9 deletions(-)
|
|
|
|
--- a/drivers/net/phy/phylink.c
|
|
+++ b/drivers/net/phy/phylink.c
|
|
@@ -155,6 +155,23 @@ static const char *phylink_an_mode_str(u
|
|
return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown";
|
|
}
|
|
|
|
+static int phylink_validate_mac_and_pcs(struct phylink *pl,
|
|
+ unsigned long *supported,
|
|
+ struct phylink_link_state *state)
|
|
+{
|
|
+ struct phylink_pcs *pcs;
|
|
+
|
|
+ if (pl->mac_ops->mac_select_pcs) {
|
|
+ pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
|
|
+ if (IS_ERR(pcs))
|
|
+ return PTR_ERR(pcs);
|
|
+ }
|
|
+
|
|
+ pl->mac_ops->validate(pl->config, supported, state);
|
|
+
|
|
+ return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
|
|
+}
|
|
+
|
|
static int phylink_validate_any(struct phylink *pl, unsigned long *supported,
|
|
struct phylink_link_state *state)
|
|
{
|
|
@@ -170,9 +187,10 @@ static int phylink_validate_any(struct p
|
|
|
|
t = *state;
|
|
t.interface = intf;
|
|
- pl->mac_ops->validate(pl->config, s, &t);
|
|
- linkmode_or(all_s, all_s, s);
|
|
- linkmode_or(all_adv, all_adv, t.advertising);
|
|
+ if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
|
|
+ linkmode_or(all_s, all_s, s);
|
|
+ linkmode_or(all_adv, all_adv, t.advertising);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -194,9 +212,7 @@ static int phylink_validate(struct phyli
|
|
return -EINVAL;
|
|
}
|
|
|
|
- pl->mac_ops->validate(pl->config, supported, state);
|
|
-
|
|
- return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
|
|
+ return phylink_validate_mac_and_pcs(pl, supported, state);
|
|
}
|
|
|
|
static int phylink_parse_fixedlink(struct phylink *pl,
|
|
@@ -486,10 +502,21 @@ static void phylink_mac_pcs_an_restart(s
|
|
static void phylink_major_config(struct phylink *pl, bool restart,
|
|
const struct phylink_link_state *state)
|
|
{
|
|
+ struct phylink_pcs *pcs = NULL;
|
|
int err;
|
|
|
|
phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
|
|
|
|
+ if (pl->mac_ops->mac_select_pcs) {
|
|
+ pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
|
|
+ if (IS_ERR(pcs)) {
|
|
+ phylink_err(pl,
|
|
+ "mac_select_pcs unexpectedly failed: %pe\n",
|
|
+ pcs);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
if (pl->mac_ops->mac_prepare) {
|
|
err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
|
|
state->interface);
|
|
@@ -500,6 +527,12 @@ static void phylink_major_config(struct
|
|
}
|
|
}
|
|
|
|
+ /* If we have a new PCS, switch to the new PCS after preparing the MAC
|
|
+ * for the change.
|
|
+ */
|
|
+ if (pcs)
|
|
+ phylink_set_pcs(pl, pcs);
|
|
+
|
|
phylink_mac_config(pl, state);
|
|
|
|
if (pl->pcs_ops) {
|
|
@@ -879,6 +912,14 @@ struct phylink *phylink_create(struct ph
|
|
struct phylink *pl;
|
|
int ret;
|
|
|
|
+ /* Validate the supplied configuration */
|
|
+ if (mac_ops->mac_select_pcs &&
|
|
+ phy_interface_empty(config->supported_interfaces)) {
|
|
+ dev_err(config->dev,
|
|
+ "phylink: error: empty supported_interfaces but mac_select_pcs() method present\n");
|
|
+ return ERR_PTR(-EINVAL);
|
|
+ }
|
|
+
|
|
pl = kzalloc(sizeof(*pl), GFP_KERNEL);
|
|
if (!pl)
|
|
return ERR_PTR(-ENOMEM);
|
|
@@ -947,9 +988,10 @@ EXPORT_SYMBOL_GPL(phylink_create);
|
|
* @pl: a pointer to a &struct phylink returned from phylink_create()
|
|
* @pcs: a pointer to the &struct phylink_pcs
|
|
*
|
|
- * Bind the MAC PCS to phylink. This may be called after phylink_create(),
|
|
- * in mac_prepare() or mac_config() methods if it is desired to dynamically
|
|
- * change the PCS.
|
|
+ * Bind the MAC PCS to phylink. This may be called after phylink_create().
|
|
+ * If it is desired to dynamically change the PCS, then the preferred method
|
|
+ * is to use mac_select_pcs(), but it may also be called in mac_prepare()
|
|
+ * or mac_config().
|
|
*
|
|
* Please note that there are behavioural changes with the mac_config()
|
|
* callback if a PCS is present (denoting a newer setup) so removing a PCS
|
|
@@ -960,6 +1002,14 @@ void phylink_set_pcs(struct phylink *pl,
|
|
{
|
|
pl->pcs = pcs;
|
|
pl->pcs_ops = pcs->ops;
|
|
+
|
|
+ if (!pl->phylink_disable_state &&
|
|
+ pl->cfg_link_an_mode == MLO_AN_INBAND) {
|
|
+ if (pl->config->pcs_poll || pcs->poll)
|
|
+ mod_timer(&pl->link_poll, jiffies + HZ);
|
|
+ else
|
|
+ del_timer(&pl->link_poll);
|
|
+ }
|
|
}
|
|
EXPORT_SYMBOL_GPL(phylink_set_pcs);
|
|
|
|
--- a/include/linux/phylink.h
|
|
+++ b/include/linux/phylink.h
|
|
@@ -86,6 +86,7 @@ struct phylink_config {
|
|
/**
|
|
* struct phylink_mac_ops - MAC operations structure.
|
|
* @validate: Validate and update the link configuration.
|
|
+ * @mac_select_pcs: Select a PCS for the interface mode.
|
|
* @mac_pcs_get_state: Read the current link state from the hardware.
|
|
* @mac_prepare: prepare for a major reconfiguration of the interface.
|
|
* @mac_config: configure the MAC for the selected mode and state.
|
|
@@ -100,6 +101,8 @@ struct phylink_mac_ops {
|
|
void (*validate)(struct phylink_config *config,
|
|
unsigned long *supported,
|
|
struct phylink_link_state *state);
|
|
+ struct phylink_pcs *(*mac_select_pcs)(struct phylink_config *config,
|
|
+ phy_interface_t interface);
|
|
void (*mac_pcs_get_state)(struct phylink_config *config,
|
|
struct phylink_link_state *state);
|
|
int (*mac_prepare)(struct phylink_config *config, unsigned int mode,
|
|
@@ -152,6 +155,21 @@ struct phylink_mac_ops {
|
|
*/
|
|
void validate(struct phylink_config *config, unsigned long *supported,
|
|
struct phylink_link_state *state);
|
|
+/**
|
|
+ * mac_select_pcs: Select a PCS for the interface mode.
|
|
+ * @config: a pointer to a &struct phylink_config.
|
|
+ * @interface: PHY interface mode for PCS
|
|
+ *
|
|
+ * Return the &struct phylink_pcs for the specified interface mode, or
|
|
+ * NULL if none is required, or an error pointer on error.
|
|
+ *
|
|
+ * This must not modify any state. It is used to query which PCS should
|
|
+ * be used. Phylink will use this during validation to ensure that the
|
|
+ * configuration is valid, and when setting a configuration to internally
|
|
+ * set the PCS that will be used.
|
|
+ */
|
|
+struct phylink_pcs *mac_select_pcs(struct phylink_config *config,
|
|
+ phy_interface_t interface);
|
|
|
|
/**
|
|
* mac_pcs_get_state() - Read the current inband link state from the hardware
|