]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: index links per SerDes via pcs-handle cell
authorJonas Jelonek <jelonek.jonas@gmail.com>
Mon, 25 May 2026 14:00:32 +0000 (14:00 +0000)
committerJonas Jelonek <jelonek.jonas@gmail.com>
Sun, 31 May 2026 10:52:40 +0000 (12:52 +0200)
Move the rtpcs_link pointer array from rtpcs_ctrl (keyed by global
DSA port) into rtpcs_serdes (keyed by the per-SerDes link index).
This matches how the hardware is structured -- a SerDes hosts up to
RTPCS_MAX_LINKS_PER_SDS PCS links -- and aligns the in-driver
addressing with the cell the DTSes just gained on pcs-handle, so the
upcoming fwnode_pcs resolver becomes a direct sds->link[cell] lookup.

rtpcs_create() takes a new link_idx parameter and stores into
sds->link[link_idx] instead of ctrl->link[port]; the DSA glue switches
its phandle lookup to of_parse_phandle_with_args() and forwards the
cell. The port number stays on rtpcs_link for legacy callers that
still need it. Bounds and double-bind checks (-EINVAL, -EBUSY) guard
against malformed DT references that would otherwise OOB or silently
overwrite an existing link.

Drops RTPCS_PORT_CNT, whose only user was the relocated array, and
fixes a pre-existing of_node_put leak on the pcs-handle phandle in
the DSA glue as a side effect of the parse-with-args conversion.

Link: https://github.com/openwrt/openwrt/pull/23539
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c
target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c

index 6e0197d2b391694f1732415edf209ee6a58e77bd..45f645065b958c3ee7c493c2d09195b236575544 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "rtl-otto.h"
 
-struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int port);
+struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int link_idx, int port);
 
 int rtldsa_port_get_stp_state(struct rtl838x_switch_priv *priv, int port)
 {
@@ -254,7 +254,9 @@ static bool rtldsa_phys_load_deferred(void)
 
 static int rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
 {
-       struct device_node *dn, *phy_node, *pcs_node, *led_node;
+       struct device_node *dn, *phy_node, *led_node;
+       struct of_phandle_args pcs_args;
+       bool has_pcs;
        u32 pn;
 
        /* Check if all busses of Realtek mdio controller are registered */
@@ -292,15 +294,18 @@ static int rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
                if (of_property_read_u32(dn, "reg", &pn))
                        continue;
 
-               pcs_node = of_parse_phandle(dn, "pcs-handle", 0);
+               has_pcs = !of_parse_phandle_with_args(dn, "pcs-handle", "#pcs-cells",
+                                                     0, &pcs_args);
                phy_node = of_parse_phandle(dn, "phy-handle", 0);
-               if (pn != priv->r->cpu_port && !phy_node && !pcs_node) {
+               if (pn != priv->r->cpu_port && !phy_node && !has_pcs) {
                        dev_err(priv->dev, "Port node %d has neither pcs-handle nor phy-handle\n", pn);
                        continue;
                }
 
-               if (pcs_node) {
-                       priv->ports[pn].pcs = rtpcs_create(priv->dev, pcs_node, pn);
+               if (has_pcs) {
+                       priv->ports[pn].pcs = rtpcs_create(priv->dev, pcs_args.np,
+                                                          pcs_args.args[0], pn);
+                       of_node_put(pcs_args.np);
                        if (IS_ERR(priv->ports[pn].pcs)) {
                                dev_err(priv->dev, "port %u failed to create PCS instance: %ld\n",
                                        pn, PTR_ERR(priv->ports[pn].pcs));
index 6833d1d372cd4a8209f8f8cd439849609afacd29..a7bfb6cfc9f98dc770435246e437ce00af92c7b3 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/regmap.h>
 
 #define RTPCS_SDS_CNT                          14
-#define RTPCS_PORT_CNT                         57
 #define RTPCS_MAX_LINKS_PER_SDS                        8
 
 #define RTPCS_SPEED_10                         0
@@ -221,6 +220,7 @@ struct rtpcs_serdes {
                struct regmap_field *mac_mode_force;    /* nullable, 931x only */
                struct regmap_field *usxgmii_submode;   /* nullable, 93xx only */
        } swcore_regs;
+       struct rtpcs_link *link[RTPCS_MAX_LINKS_PER_SDS];
 
        enum rtpcs_sds_mode hw_mode;
        u8 id;
@@ -234,7 +234,6 @@ struct rtpcs_ctrl {
        struct mii_bus *bus;
        const struct rtpcs_config *cfg;
        struct rtpcs_serdes serdes[RTPCS_SDS_CNT];
-       struct rtpcs_link *link[RTPCS_PORT_CNT];
        struct mutex lock;
 
        /* meaning and source may be family-specific */
@@ -4132,8 +4131,8 @@ out:
        return ret;
 }
 
-struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int port);
-struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int port)
+struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int link_idx, int port);
+struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int link_idx, int port)
 {
        struct platform_device *pdev;
        struct device_node *pcs_np;
@@ -4177,6 +4176,15 @@ struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int
        if (rtpcs_sds_read(sds, 0, 0) < 0)
                return ERR_PTR(-EINVAL);
 
+       if (link_idx >= RTPCS_MAX_LINKS_PER_SDS) {
+               put_device(&pdev->dev);
+               return ERR_PTR(-EINVAL);
+       }
+       if (sds->link[link_idx]) {
+               put_device(&pdev->dev);
+               return ERR_PTR(-EBUSY);
+       }
+
        link = devm_kzalloc(ctrl->dev, sizeof(*link), GFP_KERNEL);
        if (!link) {
                put_device(&pdev->dev);
@@ -4190,10 +4198,10 @@ struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int
        link->sds = sds;
        link->pcs.ops = ctrl->cfg->pcs_ops;
 
-       ctrl->link[port] = link;
-
-       dev_dbg(ctrl->dev, "phylink_pcs created, port %d, sds %d\n", port, sds_id);
+       sds->link[link_idx] = link;
 
+       dev_dbg(ctrl->dev, "phylink_pcs created, port %d, sds %d, link_idx %d\n",
+               port, sds_id, link_idx);
        return &link->pcs;
 }
 EXPORT_SYMBOL(rtpcs_create);