realtek: pcs: derive SerDes link count from DT at probe time
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>
This commit is contained in:
parent
a7bd3b147e
commit
15593de376
@ -252,21 +252,27 @@
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -265,45 +265,59 @@
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -252,39 +252,51 @@
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -284,45 +284,59 @@
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user