]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: derive SerDes link count from DT at probe time 23484/head
authorJonas Jelonek <jelonek.jonas@gmail.com>
Fri, 22 May 2026 20:14:20 +0000 (20:14 +0000)
committerJonas Jelonek <jelonek.jonas@gmail.com>
Sat, 23 May 2026 09:02:15 +0000 (11:02 +0200)
Previously, sds->num_of_links was incremented from rtpcs_create() as
each DSA port bound its phylink_pcs. The count therefore relied on a
temporal contract (DSA must finish enumerating before pcs_config runs)
and on rtpcs_create() being the single chokepoint for all consumers.

Replace this with a probe-time scan of pcs-handle references in the
live OF tree: for every available consumer node carrying a pcs-handle
property pointing at one of our SerDes subnodes, bump that SerDes'
num_of_links. After the scan, the count is final regardless of when
or whether DSA later calls in.

To allow of_parse_phandle_with_args() to walk the property correctly,
add #pcs-cells = <0> to every serdes@N node in the 838x/839x/930x/931x
.dtsi files. A future cell-bearing form remains possible without
touching the scan.

Over-references (DT pointing more consumers at one SerDes than the
hardware can carry) are clamped at RTPCS_MAX_LINKS_PER_SDS and warned
about, but do not fail probe — the correctly-wired ports on that
SerDes still come up, and only the surplus reference is dropped.

The bounds check and the bare ++ in rtpcs_create() become redundant
under the scan-driven count and are removed.

This decouples num_of_links from DSA call ordering and is a prereq
for migrating to fwnode_pcs providers, where rtpcs_create() goes away
as the centralised counter.

Link: https://github.com/openwrt/openwrt/pull/23484
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
target/linux/realtek/dts/rtl838x.dtsi
target/linux/realtek/dts/rtl839x.dtsi
target/linux/realtek/dts/rtl930x.dtsi
target/linux/realtek/dts/rtl931x.dtsi
target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c

index 911abe7ad0cffe9a0237ba914ed0b72d86485116..900004a0e8929189ea6a52f0a8c9433472c7e30e 100644 (file)
 
                        serdes0: serdes@0 {
                                reg = <0>;
+                               #pcs-cells = <0>;
                        };
                        serdes1: serdes@1 {
                                reg = <1>;
+                               #pcs-cells = <0>;
                        };
                        serdes2: serdes@2 {
                                reg = <2>;
+                               #pcs-cells = <0>;
                        };
                        serdes3: serdes@3 {
                                reg = <3>;
+                               #pcs-cells = <0>;
                        };
                        serdes4: serdes@4 {
                                reg = <4>;
+                               #pcs-cells = <0>;
                        };
                        serdes5: serdes@5 {
                                reg = <5>;
+                               #pcs-cells = <0>;
                        };
                };
 
index 48b383687d5649b736a3661561491915b18201c7..ed388948f753e46b2c9b5cd4d88fb89907884eed 100644 (file)
 
                        serdes0: serdes@0 {
                                reg = <0>;
+                               #pcs-cells = <0>;
                        };
                        serdes1: serdes@1 {
                                reg = <1>;
+                               #pcs-cells = <0>;
                        };
                        serdes2: serdes@2 {
                                reg = <2>;
+                               #pcs-cells = <0>;
                        };
                        serdes3: serdes@3 {
                                reg = <3>;
+                               #pcs-cells = <0>;
                        };
                        serdes4: serdes@4 {
                                reg = <4>;
+                               #pcs-cells = <0>;
                        };
                        serdes5: serdes@5 {
                                reg = <5>;
+                               #pcs-cells = <0>;
                        };
                        serdes6: serdes@6 {
                                reg = <6>;
+                               #pcs-cells = <0>;
                        };
                        serdes7: serdes@7 {
                                reg = <7>;
+                               #pcs-cells = <0>;
                        };
                        serdes8: serdes@8 {
                                reg = <8>;
+                               #pcs-cells = <0>;
                        };
                        serdes9: serdes@9 {
                                reg = <9>;
+                               #pcs-cells = <0>;
                        };
                        serdes10: serdes@10 {
                                reg = <10>;
+                               #pcs-cells = <0>;
                        };
                        serdes11: serdes@11 {
                                reg = <11>;
+                               #pcs-cells = <0>;
                        };
                        serdes12: serdes@12 {
                                reg = <12>;
+                               #pcs-cells = <0>;
                        };
                        serdes13: serdes@13 {
                                reg = <13>;
+                               #pcs-cells = <0>;
                        };
                };
 
index 3096c78d8d85d4f50520f964b80c44e0dbd92689..8474d5013b5ad35775f18a27c5fd0dcc07ac0776 100644 (file)
 
                        serdes0: serdes@0 {
                                reg = <0>;
+                               #pcs-cells = <0>;
                        };
                        serdes1: serdes@1 {
                                reg = <1>;
+                               #pcs-cells = <0>;
                        };
                        serdes2: serdes@2 {
                                reg = <2>;
+                               #pcs-cells = <0>;
                        };
                        serdes3: serdes@3 {
                                reg = <3>;
+                               #pcs-cells = <0>;
                        };
                        serdes4: serdes@4 {
                                reg = <4>;
+                               #pcs-cells = <0>;
                        };
                        serdes5: serdes@5 {
                                reg = <5>;
+                               #pcs-cells = <0>;
                        };
                        serdes6: serdes@6 {
                                reg = <6>;
+                               #pcs-cells = <0>;
                        };
                        serdes7: serdes@7 {
                                reg = <7>;
+                               #pcs-cells = <0>;
                        };
                        serdes8: serdes@8 {
                                reg = <8>;
+                               #pcs-cells = <0>;
                        };
                        serdes9: serdes@9 {
                                reg = <9>;
+                               #pcs-cells = <0>;
                        };
                        serdes10: serdes@10 {
                                reg = <10>;
+                               #pcs-cells = <0>;
                        };
                        serdes11: serdes@11 {
                                reg = <11>;
+                               #pcs-cells = <0>;
                        };
                };
 
index 1e1b855dfbb45f055024d8c19d3651ce081b59d5..c6581eb30a5072143f63873d3802dd12cc1f5566 100644 (file)
 
                        serdes0: serdes@0 {
                                reg = <0>;
+                               #pcs-cells = <0>;
                        };
                        serdes1: serdes@1 {
                                reg = <1>;
+                               #pcs-cells = <0>;
                        };
                        serdes2: serdes@2 {
                                reg = <2>;
+                               #pcs-cells = <0>;
                        };
                        serdes3: serdes@3 {
                                reg = <3>;
+                               #pcs-cells = <0>;
                        };
                        serdes4: serdes@4 {
                                reg = <4>;
+                               #pcs-cells = <0>;
                        };
                        serdes5: serdes@5 {
                                reg = <5>;
+                               #pcs-cells = <0>;
                        };
                        serdes6: serdes@6 {
                                reg = <6>;
+                               #pcs-cells = <0>;
                        };
                        serdes7: serdes@7 {
                                reg = <7>;
+                               #pcs-cells = <0>;
                        };
                        serdes8: serdes@8 {
                                reg = <8>;
+                               #pcs-cells = <0>;
                        };
                        serdes9: serdes@9 {
                                reg = <9>;
+                               #pcs-cells = <0>;
                        };
                        serdes10: serdes@10 {
                                reg = <10>;
+                               #pcs-cells = <0>;
                        };
                        serdes11: serdes@11 {
                                reg = <11>;
+                               #pcs-cells = <0>;
                        };
                        serdes12: serdes@12 {
                                reg = <12>;
+                               #pcs-cells = <0>;
                        };
                        serdes13: serdes@13 {
                                reg = <13>;
+                               #pcs-cells = <0>;
                        };
                };
 
index 1668c61fe4e29e7b784461a49530e1535f95b341..c93a08c1fa05af09e69b9c3eaa64910fd38bd4ce 100644 (file)
@@ -4107,8 +4107,6 @@ struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int
        sds = &ctrl->serdes[sds_id];
        if (rtpcs_sds_read(sds, 0, 0) < 0)
                return ERR_PTR(-EINVAL);
-       if (sds->num_of_links >= RTPCS_MAX_LINKS_PER_SDS)
-               return ERR_PTR(-ERANGE);
 
        link = devm_kzalloc(ctrl->dev, sizeof(*link), GFP_KERNEL);
        if (!link) {
@@ -4118,7 +4116,6 @@ struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int
 
        device_link_add(dev, ctrl->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
 
-       sds->num_of_links++;
        link->ctrl = ctrl;
        link->port = port;
        link->sds = sds;
@@ -4166,6 +4163,41 @@ static void rtpcs_sds_put_of_node(void *data)
        of_node_put(sds->of_node);
 }
 
+static void rtpcs_count_links(struct rtpcs_ctrl *ctrl)
+{
+       struct device_node *consumer __free(device_node) = NULL;
+       struct of_phandle_args args;
+
+       for_each_node_with_property(consumer, "pcs-handle") {
+               int idx = 0;
+
+               if (!of_device_is_available(consumer))
+                       continue;
+
+               while (!of_parse_phandle_with_args(consumer, "pcs-handle",
+                                                  "#pcs-cells", idx++, &args)) {
+                       struct device_node *arg_np __free(device_node) = args.np;
+
+                       for (int s = 0; s < ctrl->cfg->serdes_count; s++) {
+                               struct rtpcs_serdes *sds = &ctrl->serdes[s];
+
+                               if (arg_np != sds->of_node)
+                                       continue;
+
+                               if (sds->num_of_links >= RTPCS_MAX_LINKS_PER_SDS) {
+                                       dev_warn(ctrl->dev,
+                                                "%pOF: pcs-handle to sds%u exceeds max %u, clamping\n",
+                                                consumer, sds->id, RTPCS_MAX_LINKS_PER_SDS);
+                                       break;
+                               }
+
+                               sds->num_of_links++;
+                               break;
+                       }
+               }
+       }
+}
+
 static int rtpcs_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -4220,6 +4252,8 @@ static int rtpcs_probe(struct platform_device *pdev)
                        return ret;
        }
 
+       rtpcs_count_links(ctrl);
+
        if (ctrl->cfg->init) {
                ret = ctrl->cfg->init(ctrl);
                if (ret)