generic: update pending PCS patch with .fill_available_pcs OP

While implementing standalone PCS support for DSA, it was found that making
the MAC driver passing the available_pcs array is limiting and problematic
for memory handling and allocation. To better handle this, change the logic
and make phylink allocate the struct and make the MAC driver implement a
function in phylink_config .fill_available_pcs to fill the PCS array.

Update the Airoha and Mediatek driver to reflect this new implementation.

Link: https://github.com/openwrt/openwrt/pull/23413
(cherry picked from commit 627cd79e1c)
Link: https://github.com/openwrt/openwrt/pull/24823
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
Christian Marangi committed 2026-09-30 08:52:30 +02:00
1 parent b08e87dd98
commit bcbf4a406a
5 files changed
+85 -31

No files matched your search

@@ -210,13 +210,13 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+ break;
+ }
+ }
+
- pcs_changed = pl->pcs != pcs;
+ if (!pcs_found) {
+ phylink_err(pl,
+ "couldn't find a PCS for %s\n",
+ phy_modes(state->interface));
- pcs_changed = pl->pcs != pcs;
+
+ pl->major_config_failed = true;
+ return;
+ }
@@ -245,28 +245,70 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
pl->pcs = pcs;
}
@@ -1931,8 +2006,9 @@ struct phylink *phylink_create(struct ph
@@ -1909,6 +1984,44 @@ int phylink_set_fixed_link(struct phylin
}
EXPORT_SYMBOL_GPL(phylink_set_fixed_link);
+static int phylink_fill_available_pcs(struct phylink *pl,
+ struct phylink_config *config)
+{
+ struct phylink_pcs **pcss;
+ int i, ret;
+
+ if (!config->num_available_pcs)
+ return 0;
+
+ if (!config->fill_available_pcs) {
+ dev_err(config->dev,
+ "phylink: error: num_available_pcs defined but no fill_available_pcs\n");
+ return -EINVAL;
+ }
+
+ pcss = kcalloc(config->num_available_pcs, sizeof(*pcss), GFP_KERNEL);
+ if (!pcss)
+ return -ENOMEM;
+
+ ret = config->fill_available_pcs(config, pcss, config->num_available_pcs);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < config->num_available_pcs; i++) {
+ struct phylink_pcs *pcs = pcss[i];
+
+ if (!pcs)
+ continue;
+
+ list_add(&pcs->list, &pl->pcs_list);
+ }
+
+out:
+ kfree(pcss);
+
+ return ret;
+}
+
/**
* phylink_create() - create a phylink instance
* @config: a pointer to the target &struct phylink_config
@@ -1931,6 +2044,7 @@ struct phylink *phylink_create(struct ph
const struct phylink_mac_ops *mac_ops)
{
bool using_mac_select_pcs = false;
+ struct phylink_pcs *pcs;
struct phylink *pl;
- int ret;
+ int i, ret;
int ret;
/* Validate the supplied configuration */
if (phy_interface_empty(config->supported_interfaces)) {
@@ -1952,9 +2028,21 @@ struct phylink *phylink_create(struct ph
@@ -1952,9 +2066,21 @@ struct phylink *phylink_create(struct ph
mutex_init(&pl->state_mutex);
INIT_WORK(&pl->resolve, phylink_resolve);
+ INIT_LIST_HEAD(&pl->pcs_list);
+
+ /* Fill the PCS list with available PCS from phylink config */
+ for (i = 0; i < config->num_available_pcs; i++) {
+ pcs = config->available_pcs[i];
+
+ list_add(&pcs->list, &pl->pcs_list);
+ ret = phylink_fill_available_pcs(pl, config);
+ if (ret) {
+ kfree(pl);
+ return ERR_PTR(ret);
+ }
phy_interface_copy(pl->supported_interfaces,
@@ -278,7 +320,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
pl->config = config;
if (config->type == PHYLINK_NETDEV) {
@@ -2024,10 +2112,16 @@ EXPORT_SYMBOL_GPL(phylink_create);
@@ -2025,10 +2151,16 @@ EXPORT_SYMBOL_GPL(phylink_create);
*/
void phylink_destroy(struct phylink *pl)
{
@@ -295,7 +337,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
cancel_work_sync(&pl->resolve);
kfree(pl);
}
@@ -2472,6 +2566,7 @@ static irqreturn_t phylink_link_handler(
@@ -2473,6 +2605,7 @@ static irqreturn_t phylink_link_handler(
*/
void phylink_start(struct phylink *pl)
{
@@ -303,7 +345,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
bool poll = false;
ASSERT_RTNL();
@@ -2498,6 +2593,10 @@ void phylink_start(struct phylink *pl)
@@ -2499,6 +2632,10 @@ void phylink_start(struct phylink *pl)
pl->pcs_state = PCS_STATE_STARTED;
@@ -314,7 +356,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_STOPPED);
if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
@@ -2542,6 +2641,8 @@ EXPORT_SYMBOL_GPL(phylink_start);
@@ -2543,6 +2680,8 @@ EXPORT_SYMBOL_GPL(phylink_start);
*/
void phylink_stop(struct phylink *pl)
{
@@ -323,7 +365,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
ASSERT_RTNL();
if (pl->sfp_bus)
@@ -2559,6 +2660,14 @@ void phylink_stop(struct phylink *pl)
@@ -2560,6 +2699,14 @@ void phylink_stop(struct phylink *pl)
pl->pcs_state = PCS_STATE_DOWN;
phylink_pcs_disable(pl->pcs);
@@ -340,31 +382,43 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -147,7 +147,11 @@ enum phylink_op_type {
@@ -10,6 +10,7 @@ struct ethtool_cmd;
struct fwnode_handle;
struct net_device;
struct phylink;
+struct phylink_pcs;
enum {
MLO_PAUSE_NONE,
@@ -147,7 +148,13 @@ enum phylink_op_type {
* if MAC link is at %MLO_AN_FIXED mode.
* @supported_interfaces: bitmap describing which PHY_INTERFACE_MODE_xxx
* are supported by the MAC/PCS.
+ * @pcs_interfaces: bitmap describing for which PHY_INTERFACE_MODE_xxx a
+ * dedicated PCS is required.
* @mac_capabilities: MAC pause/speed/duplex capabilities.
+ * @available_pcs: array of available phylink_pcs PCS
+ * @num_available_pcs: num of available phylink_pcs PCS
+ * @fill_available_pcs: callback to fill the available PCS in the passed
+ * array struct of phylink_pcs PCS available_pcs up to
+ * num_available_pcs.
*/
struct phylink_config {
struct device *dev;
@@ -159,7 +163,11 @@ struct phylink_config {
@@ -159,7 +166,13 @@ struct phylink_config {
void (*get_fixed_state)(struct phylink_config *config,
struct phylink_link_state *state);
DECLARE_PHY_INTERFACE_MASK(supported_interfaces);
+ DECLARE_PHY_INTERFACE_MASK(pcs_interfaces);
unsigned long mac_capabilities;
+
+ struct phylink_pcs **available_pcs;
+ unsigned int num_available_pcs;
+ int (*fill_available_pcs)(struct phylink_config *config,
+ struct phylink_pcs **available_pcs,
+ unsigned int num_available_pcs);
};
void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed);
@@ -417,6 +425,9 @@ struct phylink_pcs {
@@ -417,6 +430,9 @@ struct phylink_pcs {
bool neg_mode;
bool poll;
bool rxc_always_on;
@@ -123,7 +123,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
/* If configuration of the interface failed, force the link down
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -632,6 +632,8 @@ void phylink_disconnect_phy(struct phyli
@@ -637,6 +637,8 @@ void phylink_disconnect_phy(struct phyli
int phylink_set_fixed_link(struct phylink *,
const struct phylink_link_state *);
@@ -110,9 +110,9 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
/* What interface are supported by the current link.
* Can change on removal or addition of new PCS.
@@ -2039,6 +2041,51 @@ int phylink_set_fixed_link(struct phylin
@@ -2077,6 +2079,51 @@ out:
return ret;
}
EXPORT_SYMBOL_GPL(phylink_set_fixed_link);
+static int pcs_provider_notify(struct notifier_block *self,
+ unsigned long val, void *data)
@@ -162,7 +162,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
/**
* phylink_create() - create a phylink instance
* @config: a pointer to the target &struct phylink_config
@@ -2099,6 +2146,11 @@ struct phylink *phylink_create(struct ph
@@ -2137,6 +2184,11 @@ struct phylink *phylink_create(struct ph
pl->supported_interfaces,
pcs->supported_interfaces);
@@ -46,7 +46,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
phylink_info(pl, "Link is Down\n");
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -443,6 +443,7 @@ struct phylink_pcs {
@@ -448,6 +448,7 @@ struct phylink_pcs {
* @pcs_an_restart: restart 802.3z BaseX autonegotiation.
* @pcs_link_up: program the PCS for the resolved link configuration
* (where necessary).
@@ -54,7 +54,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
* @pcs_pre_init: configure PCS components necessary for MAC hardware
* initialization e.g. RX clock for stmmac.
*/
@@ -466,6 +467,7 @@ struct phylink_pcs_ops {
@@ -471,6 +472,7 @@ struct phylink_pcs_ops {
void (*pcs_an_restart)(struct phylink_pcs *pcs);
void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int neg_mode,
phy_interface_t interface, int speed, int duplex);
@@ -11,7 +11,7 @@ Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
---
--- a/drivers/net/pcs/Kconfig
+++ b/drivers/net/pcs/Kconfig
@@ -36,6 +36,14 @@ config PCS_MTK_USXGMII
@@ -43,6 +43,14 @@ config PCS_MTK_USXGMII
1000Base-X, 2500Base-X and Cisco SGMII are supported on the same
differential pairs via an embedded LynxI PHY.
@@ -28,7 +28,7 @@ Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
depends on OF && (ARCH_RZN1 || COMPILE_TEST)
--- a/drivers/net/pcs/Makefile
+++ b/drivers/net/pcs/Makefile
@@ -7,5 +7,6 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.
@@ -8,5 +8,6 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o