diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/701-net-0281-net-mscc-ocelot-convert-to-PHYLINK.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/701-net-0281-net-mscc-ocelot-convert-to-PHYLINK.patch | 689 |
1 files changed, 689 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/701-net-0281-net-mscc-ocelot-convert-to-PHYLINK.patch b/target/linux/layerscape/patches-5.4/701-net-0281-net-mscc-ocelot-convert-to-PHYLINK.patch new file mode 100644 index 0000000000..fcf28b8667 --- /dev/null +++ b/target/linux/layerscape/patches-5.4/701-net-0281-net-mscc-ocelot-convert-to-PHYLINK.patch @@ -0,0 +1,689 @@ +From 0a2b7489bf60d24a54e16147b416f339ebe4f511 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean <vladimir.oltean@nxp.com> +Date: Mon, 18 Nov 2019 18:05:01 +0200 +Subject: [PATCH] net: mscc: ocelot: convert to PHYLINK + +This patch reworks ocelot_board.c (aka the MIPS on the VSC7514) to +register a PHYLINK instance for each port. The registration code is +local to the VSC7514, but the PHYLINK callback implementation is common +so that the Felix DSA front-end can use it as well (but DSA does its own +registration). + +Now Felix can use native PHYLINK callbacks instead of the PHYLIB +adaptation layer in DSA, which had issues supporting fixed-link slave +ports (no struct phy_device to pass to the adjust_link callback), as +well as fixed-link CPU port at 2.5Gbps. + +The old code from ocelot_port_enable and ocelot_port_disable has been +moved into ocelot_phylink_mac_link_up and ocelot_phylink_mac_link_down. + +The PHY connect operation has been moved from ocelot_port_open to +mscc_ocelot_probe in ocelot_board.c. + +The phy_set_mode_ext() call for the SerDes PHY has also been moved into +mscc_ocelot_probe from ocelot_port_open, and since that was the only +reason why a reference to it was kept in ocelot_port_private, that +reference was removed. + +Again, the usage of phy_interface_t phy_mode is now local to +mscc_ocelot_probe only, after moving the PHY connect operation. +So it was also removed from ocelot_port_private. +*Maybe* in the future, it can be added back to the common struct +ocelot_port, with the purpose of validating mismatches between +state->phy_interface and ocelot_port->phy_mode in PHYLINK callbacks. +But at the moment that is not critical, since other DSA drivers are not +doing that either. No SFP+ modules are in use with Felix/Ocelot yet, to +my knowledge. + +In-band AN is not yet supported, due to the fact that this is a mostly +mechanical patch for the moment. The mac_an_restart PHYLINK operation +needs to be implemented, as well as mac_link_state. Both are SerDes +specific, and Felix does not have its PCS configured yet (it works just +by virtue of U-Boot initialization at the moment). + +Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> +--- + drivers/net/dsa/ocelot/felix.c | 65 +++++++++---- + drivers/net/ethernet/mscc/Kconfig | 2 +- + drivers/net/ethernet/mscc/ocelot.c | 150 ++++++++++++++++-------------- + drivers/net/ethernet/mscc/ocelot.h | 13 +-- + drivers/net/ethernet/mscc/ocelot_board.c | 154 +++++++++++++++++++++++++++---- + include/soc/mscc/ocelot.h | 22 ++++- + 6 files changed, 289 insertions(+), 117 deletions(-) + +--- a/drivers/net/dsa/ocelot/felix.c ++++ b/drivers/net/dsa/ocelot/felix.c +@@ -58,14 +58,6 @@ static int felix_set_ageing_time(struct + return 0; + } + +-static void felix_adjust_link(struct dsa_switch *ds, int port, +- struct phy_device *phydev) +-{ +- struct ocelot *ocelot = ds->priv; +- +- ocelot_adjust_link(ocelot, port, phydev); +-} +- + static int felix_fdb_dump(struct dsa_switch *ds, int port, + dsa_fdb_dump_cb_t *cb, void *data) + { +@@ -185,21 +177,59 @@ static int felix_tsn_enable(struct dsa_p + } + #endif + +-static int felix_port_enable(struct dsa_switch *ds, int port, +- struct phy_device *phy) ++static void felix_phylink_validate(struct dsa_switch *ds, int port, ++ unsigned long *supported, ++ struct phylink_link_state *state) + { + struct ocelot *ocelot = ds->priv; + +- ocelot_port_enable(ocelot, port, phy); ++ ocelot_phylink_validate(ocelot, port, supported, state); ++} ++ ++static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port, ++ struct phylink_link_state *state) ++{ ++ struct ocelot *ocelot = ds->priv; ++ ++ ocelot_phylink_mac_pcs_get_state(ocelot, port, state); + + return 0; + } + +-static void felix_port_disable(struct dsa_switch *ds, int port) ++static void felix_phylink_mac_config(struct dsa_switch *ds, int port, ++ unsigned int link_an_mode, ++ const struct phylink_link_state *state) ++{ ++ struct ocelot *ocelot = ds->priv; ++ ++ ocelot_phylink_mac_config(ocelot, port, link_an_mode, state); ++} ++ ++static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port) ++{ ++ struct ocelot *ocelot = ds->priv; ++ ++ ocelot_phylink_mac_an_restart(ocelot, port); ++} ++ ++static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, ++ unsigned int link_an_mode, ++ phy_interface_t interface) ++{ ++ struct ocelot *ocelot = ds->priv; ++ ++ ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, interface); ++} ++ ++static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, ++ unsigned int link_an_mode, ++ phy_interface_t interface, ++ struct phy_device *phydev) + { + struct ocelot *ocelot = ds->priv; + +- return ocelot_port_disable(ocelot, port); ++ ocelot_phylink_mac_link_up(ocelot, port, link_an_mode, interface, ++ phydev); + } + + static void felix_get_strings(struct dsa_switch *ds, int port, +@@ -417,9 +447,12 @@ static const struct dsa_switch_ops felix + .get_ethtool_stats = felix_get_ethtool_stats, + .get_sset_count = felix_get_sset_count, + .get_ts_info = felix_get_ts_info, +- .adjust_link = felix_adjust_link, +- .port_enable = felix_port_enable, +- .port_disable = felix_port_disable, ++ .phylink_validate = felix_phylink_validate, ++ .phylink_mac_link_state = felix_phylink_mac_pcs_get_state, ++ .phylink_mac_config = felix_phylink_mac_config, ++ .phylink_mac_an_restart = felix_phylink_mac_an_restart, ++ .phylink_mac_link_down = felix_phylink_mac_link_down, ++ .phylink_mac_link_up = felix_phylink_mac_link_up, + .port_fdb_dump = felix_fdb_dump, + .port_fdb_add = felix_fdb_add, + .port_fdb_del = felix_fdb_del, +--- a/drivers/net/ethernet/mscc/Kconfig ++++ b/drivers/net/ethernet/mscc/Kconfig +@@ -15,7 +15,7 @@ config MSCC_OCELOT_SWITCH + tristate "Ocelot switch driver" + depends on NET_SWITCHDEV + depends on HAS_IOMEM +- select PHYLIB ++ select PHYLINK + select REGMAP_MMIO + help + This driver supports the Ocelot network switch device. +--- a/drivers/net/ethernet/mscc/ocelot.c ++++ b/drivers/net/ethernet/mscc/ocelot.c +@@ -13,7 +13,7 @@ + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/netdevice.h> +-#include <linux/phy.h> ++#include <linux/phylink.h> + #include <linux/ptp_clock_kernel.h> + #include <linux/skbuff.h> + #include <linux/iopoll.h> +@@ -406,18 +406,66 @@ static u16 ocelot_wm_enc(u16 value) + return value; + } + +-void ocelot_adjust_link(struct ocelot *ocelot, int port, +- struct phy_device *phydev) ++void ocelot_phylink_validate(struct ocelot *ocelot, int port, ++ unsigned long *supported, ++ struct phylink_link_state *state) ++{ ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; ++ ++ if (state->interface != PHY_INTERFACE_MODE_NA && ++ state->interface != PHY_INTERFACE_MODE_GMII && ++ state->interface != PHY_INTERFACE_MODE_SGMII && ++ state->interface != PHY_INTERFACE_MODE_QSGMII) { ++ bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ return; ++ } ++ ++ /* No half-duplex. */ ++ phylink_set_port_modes(mask); ++ phylink_set(mask, Autoneg); ++ phylink_set(mask, Pause); ++ phylink_set(mask, Asym_Pause); ++ phylink_set(mask, 10baseT_Full); ++ phylink_set(mask, 100baseT_Full); ++ phylink_set(mask, 1000baseT_Full); ++ phylink_set(mask, 2500baseT_Full); ++ ++ bitmap_and(supported, supported, mask, ++ __ETHTOOL_LINK_MODE_MASK_NBITS); ++ bitmap_and(state->advertising, state->advertising, mask, ++ __ETHTOOL_LINK_MODE_MASK_NBITS); ++} ++EXPORT_SYMBOL(ocelot_phylink_validate); ++ ++void ocelot_phylink_mac_pcs_get_state(struct ocelot *ocelot, int port, ++ struct phylink_link_state *state) ++{ ++ state->link = 1; ++} ++EXPORT_SYMBOL(ocelot_phylink_mac_pcs_get_state); ++ ++void ocelot_phylink_mac_an_restart(struct ocelot *ocelot, int port) ++{ ++ /* Not supported */ ++} ++EXPORT_SYMBOL(ocelot_phylink_mac_an_restart); ++ ++void ocelot_phylink_mac_config(struct ocelot *ocelot, int port, ++ unsigned int link_an_mode, ++ const struct phylink_link_state *state) + { + int speed, mac_speed, mac_mode = DEV_MAC_MODE_CFG_FDX_ENA; + struct ocelot_port *ocelot_port = ocelot->ports[port]; ++ u32 mac_fc_cfg; + + if (ocelot->quirks & OCELOT_PCS_PERFORMS_RATE_ADAPTATION) + speed = SPEED_1000; + else +- speed = phydev->speed; ++ speed = state->speed; + + switch (speed) { ++ case SPEED_UNKNOWN: ++ return; + case SPEED_10: + mac_speed = OCELOT_SPEED_10; + break; +@@ -433,16 +481,11 @@ void ocelot_adjust_link(struct ocelot *o + mac_mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA; + break; + default: +- dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n", ++ dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", + port, speed); + return; + } + +- phy_print_status(phydev); +- +- if (!phydev->link) +- return; +- + /* Only full duplex supported for now */ + ocelot_port_writel(ocelot_port, mac_mode, DEV_MAC_MODE_CFG); + +@@ -469,27 +512,36 @@ void ocelot_adjust_link(struct ocelot *o + QSYS_SWITCH_PORT_MODE, port); + + /* Flow control */ +- ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | +- SYS_MAC_FC_CFG_RX_FC_ENA | SYS_MAC_FC_CFG_TX_FC_ENA | +- SYS_MAC_FC_CFG_ZERO_PAUSE_ENA | +- SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | +- SYS_MAC_FC_CFG_FC_LINK_SPEED(mac_speed), +- SYS_MAC_FC_CFG, port); ++ mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(mac_speed); ++ if (state->pause & MLO_PAUSE_RX) ++ mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; ++ if (state->pause & MLO_PAUSE_TX) ++ mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | ++ SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | ++ SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | ++ SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; ++ ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); ++ + ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); + } +-EXPORT_SYMBOL(ocelot_adjust_link); ++EXPORT_SYMBOL(ocelot_phylink_mac_config); + +-static void ocelot_port_adjust_link(struct net_device *dev) ++void ocelot_phylink_mac_link_down(struct ocelot *ocelot, int port, ++ unsigned int link_an_mode, ++ phy_interface_t interface) + { +- struct ocelot_port_private *priv = netdev_priv(dev); +- struct ocelot *ocelot = priv->port.ocelot; +- int port = priv->chip_port; ++ struct ocelot_port *ocelot_port = ocelot->ports[port]; + +- ocelot_adjust_link(ocelot, port, dev->phydev); ++ ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); ++ ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, ++ QSYS_SWITCH_PORT_MODE, port); + } ++EXPORT_SYMBOL(ocelot_phylink_mac_link_down); + +-void ocelot_port_enable(struct ocelot *ocelot, int port, +- struct phy_device *phy) ++void ocelot_phylink_mac_link_up(struct ocelot *ocelot, int port, ++ unsigned int link_an_mode, ++ phy_interface_t interface, ++ struct phy_device *phy) + { + /* Enable receiving frames on the port, and activate auto-learning of + * MAC addresses. +@@ -499,62 +551,22 @@ void ocelot_port_enable(struct ocelot *o + ANA_PORT_PORT_CFG_PORTID_VAL(port), + ANA_PORT_PORT_CFG, port); + } +-EXPORT_SYMBOL(ocelot_port_enable); ++EXPORT_SYMBOL(ocelot_phylink_mac_link_up); + + static int ocelot_port_open(struct net_device *dev) + { + struct ocelot_port_private *priv = netdev_priv(dev); +- struct ocelot *ocelot = priv->port.ocelot; +- int port = priv->chip_port; +- int err; +- +- if (priv->serdes) { +- err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET, +- priv->phy_mode); +- if (err) { +- netdev_err(dev, "Could not set mode of SerDes\n"); +- return err; +- } +- } +- +- err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link, +- priv->phy_mode); +- if (err) { +- netdev_err(dev, "Could not attach to PHY\n"); +- return err; +- } + +- dev->phydev = priv->phy; +- +- phy_attached_info(priv->phy); +- phy_start(priv->phy); +- +- ocelot_port_enable(ocelot, port, priv->phy); ++ phylink_start(priv->phylink); + + return 0; + } + +-void ocelot_port_disable(struct ocelot *ocelot, int port) +-{ +- struct ocelot_port *ocelot_port = ocelot->ports[port]; +- +- ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); +- ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, +- QSYS_SWITCH_PORT_MODE, port); +-} +-EXPORT_SYMBOL(ocelot_port_disable); +- + static int ocelot_port_stop(struct net_device *dev) + { + struct ocelot_port_private *priv = netdev_priv(dev); +- struct ocelot *ocelot = priv->port.ocelot; +- int port = priv->chip_port; +- +- phy_disconnect(priv->phy); +- +- dev->phydev = NULL; + +- ocelot_port_disable(ocelot, port); ++ phylink_stop(priv->phylink); + + return 0; + } +@@ -2251,8 +2263,7 @@ void ocelot_init_port(struct ocelot *oce + EXPORT_SYMBOL(ocelot_init_port); + + int ocelot_probe_port(struct ocelot *ocelot, u8 port, +- void __iomem *regs, +- struct phy_device *phy) ++ void __iomem *regs) + { + struct ocelot_port_private *priv; + struct ocelot_port *ocelot_port; +@@ -2265,7 +2276,6 @@ int ocelot_probe_port(struct ocelot *oce + SET_NETDEV_DEV(dev, ocelot->dev); + priv = netdev_priv(dev); + priv->dev = dev; +- priv->phy = phy; + priv->chip_port = port; + ocelot_port = &priv->port; + ocelot_port->ocelot = ocelot; +--- a/drivers/net/ethernet/mscc/ocelot.h ++++ b/drivers/net/ethernet/mscc/ocelot.h +@@ -12,8 +12,7 @@ + #include <linux/etherdevice.h> + #include <linux/if_vlan.h> + #include <linux/net_tstamp.h> +-#include <linux/phy.h> +-#include <linux/phy/phy.h> ++#include <linux/phylink.h> + #include <linux/platform_device.h> + #include <linux/ptp_clock_kernel.h> + #include <linux/regmap.h> +@@ -65,14 +64,12 @@ struct ocelot_multicast { + struct ocelot_port_private { + struct ocelot_port port; + struct net_device *dev; +- struct phy_device *phy; ++ struct phylink *phylink; ++ struct phylink_config phylink_config; + u8 chip_port; + + u8 vlan_aware; + +- phy_interface_t phy_mode; +- struct phy *serdes; +- + struct ocelot_port_tc tc; + }; + +@@ -83,9 +80,7 @@ void ocelot_port_writel(struct ocelot_po + #define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val)) + + int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops); +-int ocelot_probe_port(struct ocelot *ocelot, u8 port, +- void __iomem *regs, +- struct phy_device *phy); ++int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs); + + void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, + enum ocelot_tag_prefix injection, +--- a/drivers/net/ethernet/mscc/ocelot_board.c ++++ b/drivers/net/ethernet/mscc/ocelot_board.c +@@ -13,6 +13,7 @@ + #include <linux/mfd/syscon.h> + #include <linux/skbuff.h> + #include <net/switchdev.h> ++#include <linux/phy/phy.h> + + #include "ocelot.h" + +@@ -262,6 +263,91 @@ static const struct ocelot_ops ocelot_op + .reset = ocelot_reset, + }; + ++static void ocelot_port_phylink_validate(struct phylink_config *config, ++ unsigned long *supported, ++ struct phylink_link_state *state) ++{ ++ struct net_device *ndev = to_net_dev(config->dev); ++ struct ocelot_port_private *priv = netdev_priv(ndev); ++ struct ocelot *ocelot = priv->port.ocelot; ++ int port = priv->chip_port; ++ ++ ocelot_phylink_validate(ocelot, port, supported, state); ++} ++ ++static int ++ocelot_port_phylink_mac_pcs_get_state(struct phylink_config *config, ++ struct phylink_link_state *state) ++{ ++ struct net_device *ndev = to_net_dev(config->dev); ++ struct ocelot_port_private *priv = netdev_priv(ndev); ++ struct ocelot *ocelot = priv->port.ocelot; ++ int port = priv->chip_port; ++ ++ ocelot_phylink_mac_pcs_get_state(ocelot, port, state); ++ ++ return 0; ++} ++ ++static void ocelot_port_phylink_mac_an_restart(struct phylink_config *config) ++{ ++ struct net_device *ndev = to_net_dev(config->dev); ++ struct ocelot_port_private *priv = netdev_priv(ndev); ++ struct ocelot *ocelot = priv->port.ocelot; ++ int port = priv->chip_port; ++ ++ ocelot_phylink_mac_an_restart(ocelot, port); ++} ++ ++static void ++ocelot_port_phylink_mac_config(struct phylink_config *config, ++ unsigned int link_an_mode, ++ const struct phylink_link_state *state) ++{ ++ struct net_device *ndev = to_net_dev(config->dev); ++ struct ocelot_port_private *priv = netdev_priv(ndev); ++ struct ocelot *ocelot = priv->port.ocelot; ++ int port = priv->chip_port; ++ ++ ocelot_phylink_mac_config(ocelot, port, link_an_mode, state); ++} ++ ++static void ocelot_port_phylink_mac_link_down(struct phylink_config *config, ++ unsigned int link_an_mode, ++ phy_interface_t interface) ++{ ++ struct net_device *ndev = to_net_dev(config->dev); ++ struct ocelot_port_private *priv = netdev_priv(ndev); ++ struct ocelot *ocelot = priv->port.ocelot; ++ int port = priv->chip_port; ++ ++ return ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, ++ interface); ++} ++ ++static void ocelot_port_phylink_mac_link_up(struct phylink_config *config, ++ unsigned int link_an_mode, ++ phy_interface_t interface, ++ struct phy_device *phy) ++{ ++ struct net_device *ndev = to_net_dev(config->dev); ++ struct ocelot_port_private *priv = netdev_priv(ndev); ++ struct ocelot *ocelot = priv->port.ocelot; ++ int port = priv->chip_port; ++ ++ return ocelot_phylink_mac_link_up(ocelot, port, link_an_mode, ++ interface, phy); ++} ++ ++static const struct phylink_mac_ops ocelot_phylink_ops = { ++ .validate = ocelot_port_phylink_validate, ++ .mac_link_state = ocelot_port_phylink_mac_pcs_get_state, ++ .mac_an_restart = ocelot_port_phylink_mac_an_restart, ++ .mac_config = ocelot_port_phylink_mac_config, ++ .mac_link_down = ocelot_port_phylink_mac_link_down, ++ .mac_link_up = ocelot_port_phylink_mac_link_up, ++}; ++ + static int mscc_ocelot_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +@@ -369,8 +455,6 @@ static int mscc_ocelot_probe(struct plat + for_each_available_child_of_node(ports, portnp) { + struct ocelot_port_private *priv; + struct ocelot_port *ocelot_port; +- struct device_node *phy_node; +- struct phy_device *phy; + struct resource *res; + struct phy *serdes; + void __iomem *regs; +@@ -389,16 +473,7 @@ static int mscc_ocelot_probe(struct plat + if (IS_ERR(regs)) + continue; + +- phy_node = of_parse_phandle(portnp, "phy-handle", 0); +- if (!phy_node) +- continue; +- +- phy = of_phy_find_device(phy_node); +- of_node_put(phy_node); +- if (!phy) +- continue; +- +- err = ocelot_probe_port(ocelot, port, regs, phy); ++ err = ocelot_probe_port(ocelot, port, regs); + if (err) { + of_node_put(portnp); + goto out_put_ports; +@@ -412,9 +487,7 @@ static int mscc_ocelot_probe(struct plat + if (phy_mode < 0) + phy_mode = PHY_INTERFACE_MODE_NA; + +- priv->phy_mode = phy_mode; +- +- switch (priv->phy_mode) { ++ switch (phy_mode) { + case PHY_INTERFACE_MODE_NA: + continue; + case PHY_INTERFACE_MODE_SGMII: +@@ -451,7 +524,41 @@ static int mscc_ocelot_probe(struct plat + goto out_put_ports; + } + +- priv->serdes = serdes; ++ if (serdes) { ++ err = phy_set_mode_ext(serdes, PHY_MODE_ETHERNET, ++ phy_mode); ++ if (err) { ++ dev_err(ocelot->dev, ++ "Could not set mode of SerDes\n"); ++ of_node_put(portnp); ++ goto out_put_ports; ++ } ++ } ++ ++ priv->phylink_config.dev = &priv->dev->dev; ++ priv->phylink_config.type = PHYLINK_NETDEV; ++ ++ priv->phylink = phylink_create(&priv->phylink_config, ++ of_fwnode_handle(portnp), ++ phy_mode, &ocelot_phylink_ops); ++ if (IS_ERR(priv->phylink)) { ++ dev_err(ocelot->dev, ++ "Could not create a phylink instance (%ld)\n", ++ PTR_ERR(priv->phylink)); ++ err = PTR_ERR(priv->phylink); ++ priv->phylink = NULL; ++ of_node_put(portnp); ++ goto out_put_ports; ++ } ++ ++ err = phylink_of_phy_connect(priv->phylink, portnp, 0); ++ if (err) { ++ dev_err(ocelot->dev, "Could not connect to PHY: %d\n", ++ err); ++ phylink_destroy(priv->phylink); ++ of_node_put(portnp); ++ goto out_put_ports; ++ } + } + + register_netdevice_notifier(&ocelot_netdevice_nb); +@@ -468,12 +575,27 @@ out_put_ports: + static int mscc_ocelot_remove(struct platform_device *pdev) + { + struct ocelot *ocelot = platform_get_drvdata(pdev); ++ int port; + + ocelot_deinit(ocelot); + unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb); + unregister_switchdev_notifier(&ocelot_switchdev_nb); + unregister_netdevice_notifier(&ocelot_netdevice_nb); + ++ for (port = 0; port < ocelot->num_phys_ports; port++) { ++ struct ocelot_port_private *priv; ++ ++ priv = container_of(ocelot->ports[port], ++ struct ocelot_port_private, ++ port); ++ ++ if (priv->phylink) { ++ rtnl_lock(); ++ phylink_destroy(priv->phylink); ++ rtnl_unlock(); ++ } ++ } ++ + return 0; + } + +--- a/include/soc/mscc/ocelot.h ++++ b/include/soc/mscc/ocelot.h +@@ -518,17 +518,12 @@ void ocelot_deinit(struct ocelot *ocelot + void ocelot_init_port(struct ocelot *ocelot, int port); + + /* DSA callbacks */ +-void ocelot_port_enable(struct ocelot *ocelot, int port, +- struct phy_device *phy); +-void ocelot_port_disable(struct ocelot *ocelot, int port); + void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data); + void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data); + int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset); + int ocelot_get_ts_info(struct ocelot *ocelot, int port, + struct ethtool_ts_info *info); + void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs); +-void ocelot_adjust_link(struct ocelot *ocelot, int port, +- struct phy_device *phydev); + void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, + bool vlan_aware); + void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state); +@@ -597,4 +592,21 @@ int ocelot_rtag_parse_enable(struct ocel + int ocelot_dscp_set(struct ocelot *ocelot, int port, + bool enable, const u8 dscp_ix, + struct tsn_qos_switch_dscp_conf *c); ++void ocelot_phylink_validate(struct ocelot *ocelot, int port, ++ unsigned long *supported, ++ struct phylink_link_state *state); ++void ocelot_phylink_mac_pcs_get_state(struct ocelot *ocelot, int port, ++ struct phylink_link_state *state); ++void ocelot_phylink_mac_an_restart(struct ocelot *ocelot, int port); ++void ocelot_phylink_mac_config(struct ocelot *ocelot, int port, ++ unsigned int link_an_mode, ++ const struct phylink_link_state *state); ++void ocelot_phylink_mac_link_down(struct ocelot *ocelot, int port, ++ unsigned int link_an_mode, ++ phy_interface_t interface); ++void ocelot_phylink_mac_link_up(struct ocelot *ocelot, int port, ++ unsigned int link_an_mode, ++ phy_interface_t interface, ++ struct phy_device *phy); ++ + #endif |