In order to support split PCS using PHYLINK properly, we need to add a phylink_pcs_ops structure.
Note that a DSA driver that wants to use these needs to implement all 4 of them: the DSA core checks the presence of these 4 function pointers in dsa_switch_ops and only then does it add a PCS to PHYLINK. This is done in order to preserve compatibility with drivers that have not yet been converted, or don't need, a split PCS setup. Also, when pcs_get_state() and pcs_an_restart() are present, their mac counterparts (mac_pcs_get_state(), mac_an_restart()) will no longer get called, as can be seen in phylink.c. Signed-off-by: Ioana Ciornei <ioana.cior...@nxp.com> --- Changes in v3: * patch added include/net/dsa.h | 12 ++++++++++++ net/dsa/dsa_priv.h | 1 + net/dsa/port.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 6 ++++++ 4 files changed, 65 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 50389772c597..09aa36198f4b 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -446,6 +446,18 @@ struct dsa_switch_ops { bool tx_pause, bool rx_pause); void (*phylink_fixed_state)(struct dsa_switch *ds, int port, struct phylink_link_state *state); + void (*phylink_pcs_get_state)(struct dsa_switch *ds, int port, + struct phylink_link_state *state); + int (*phylink_pcs_config)(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising); + void (*phylink_pcs_an_restart)(struct dsa_switch *ds, int port); + void (*phylink_pcs_link_up)(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, int speed, + int duplex); + /* * ethtool hardware statistics. */ diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index adecf73bd608..de8e11796178 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -169,6 +169,7 @@ int dsa_port_vid_del(struct dsa_port *dp, u16 vid); int dsa_port_link_register_of(struct dsa_port *dp); void dsa_port_link_unregister_of(struct dsa_port *dp); extern const struct phylink_mac_ops dsa_port_phylink_mac_ops; +extern const struct phylink_pcs_ops dsa_port_phylink_pcs_ops; /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/port.c b/net/dsa/port.c index e23ece229c7e..a2b0460d2593 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -592,6 +592,52 @@ const struct phylink_mac_ops dsa_port_phylink_mac_ops = { .mac_link_up = dsa_port_phylink_mac_link_up, }; +static void dsa_port_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + + ds->ops->phylink_pcs_get_state(ds, dp->index, state); +} + +static void dsa_port_pcs_an_restart(struct phylink_config *config) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + + ds->ops->phylink_pcs_an_restart(ds, dp->index); +} + +static int dsa_port_pcs_config(struct phylink_config *config, + unsigned int mode, phy_interface_t interface, + const unsigned long *advertising) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + + return ds->ops->phylink_pcs_config(ds, dp->index, mode, interface, + advertising); +} + +static void dsa_port_pcs_link_up(struct phylink_config *config, + unsigned int mode, phy_interface_t interface, + int speed, int duplex) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + + ds->ops->phylink_pcs_link_up(ds, dp->index, mode, interface, speed, + duplex); +} + +const struct phylink_pcs_ops dsa_port_phylink_pcs_ops = { + .pcs_get_state = dsa_port_pcs_get_state, + .pcs_config = dsa_port_pcs_config, + .pcs_an_restart = dsa_port_pcs_an_restart, + .pcs_link_up = dsa_port_pcs_link_up, +}; + static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable) { struct dsa_switch *ds = dp->ds; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 4c7f086a047b..8856e70f6a06 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1650,6 +1650,12 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev) if (ds->ops->get_phy_flags) phy_flags = ds->ops->get_phy_flags(ds, dp->index); + if (ds->ops->phylink_pcs_get_state && + ds->ops->phylink_pcs_an_restart && + ds->ops->phylink_pcs_config && + ds->ops->phylink_pcs_link_up) + phylink_add_pcs(dp->pl, &dsa_port_phylink_pcs_ops); + ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags); if (ret == -ENODEV && ds->slave_mii_bus) { /* We could not connect to a designated PHY or SFP, so try to -- 2.25.1