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:
parent
43562f97e7
commit
dbd9a35bf3
@ -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));
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user