1
1

realtek: pcs: index links per SerDes via pcs-handle cell

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>
This commit is contained in:
Jonas Jelonek 2026-05-25 14:00:32 +00:00
parent 43562f97e7
commit dbd9a35bf3
No known key found for this signature in database
2 changed files with 26 additions and 13 deletions

View 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));

View 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);