diff options
author | Ioana Ciornei <ioana.ciornei@nxp.com> | 2019-05-28 20:38:16 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-05-29 21:48:53 -0700 |
commit | 0e27921816ad99f78140e0c61ddf2bc515cc7e22 (patch) | |
tree | 7b4f6d6e16753929f33852549b86a1c3b0f7d791 /net | |
parent | 77373d49de22e836cf58ddbe7689d6b4b5046539 (diff) |
net: dsa: Use PHYLINK for the CPU/DSA ports
For DSA switches that do not have an .adjust_link callback, aka those
who transitioned totally to the PHYLINK-compliant API, use PHYLINK to
drive the CPU/DSA ports.
The PHYLIB usage and .adjust_link are kept but deprecated, and users are
asked to transition from it. The reason why we can't do anything for
them is because PHYLINK does not wrap the fixed-link state behind a
phydev object, so we cannot wrap .phylink_mac_config into .adjust_link
unless we fabricate a phy_device structure.
For these ports, the newly introduced PHYLINK_DEV operation type is
used and the dsa_switch device structure is passed to PHYLINK for
printing purposes. The handling of the PHYLINK_NETDEV and PHYLINK_DEV
PHYLINK instances is common from the perspective of the driver.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <olteanv@gmail.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/dsa/port.c | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/net/dsa/port.c b/net/dsa/port.c index 0051f5006248..d74bc9df1359 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -481,12 +481,15 @@ void dsa_port_phylink_mac_link_down(struct phylink_config *config, phy_interface_t interface) { struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); - struct net_device *dev = dp->slave; + struct phy_device *phydev = NULL; struct dsa_switch *ds = dp->ds; + if (dsa_is_user_port(ds, dp->index)) + phydev = dp->slave->phydev; + if (!ds->ops->phylink_mac_link_down) { - if (ds->ops->adjust_link && dev->phydev) - ds->ops->adjust_link(ds, dp->index, dev->phydev); + if (ds->ops->adjust_link && phydev) + ds->ops->adjust_link(ds, dp->index, phydev); return; } @@ -500,12 +503,11 @@ void dsa_port_phylink_mac_link_up(struct phylink_config *config, struct phy_device *phydev) { struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); - struct net_device *dev = dp->slave; struct dsa_switch *ds = dp->ds; if (!ds->ops->phylink_mac_link_up) { - if (ds->ops->adjust_link && dev->phydev) - ds->ops->adjust_link(ds, dp->index, dev->phydev); + if (ds->ops->adjust_link && phydev) + ds->ops->adjust_link(ds, dp->index, phydev); return; } @@ -599,8 +601,53 @@ static int dsa_port_fixed_link_register_of(struct dsa_port *dp) return 0; } +static int dsa_port_phylink_register(struct dsa_port *dp) +{ + struct dsa_switch *ds = dp->ds; + struct device_node *port_dn = dp->dn; + int mode, err; + + mode = of_get_phy_mode(port_dn); + if (mode < 0) + mode = PHY_INTERFACE_MODE_NA; + + dp->pl_config.dev = ds->dev; + dp->pl_config.type = PHYLINK_DEV; + + dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), + mode, &dsa_port_phylink_mac_ops); + if (IS_ERR(dp->pl)) { + pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl)); + return PTR_ERR(dp->pl); + } + + err = phylink_of_phy_connect(dp->pl, port_dn, 0); + if (err) { + pr_err("could not attach to PHY: %d\n", err); + goto err_phy_connect; + } + + rtnl_lock(); + phylink_start(dp->pl); + rtnl_unlock(); + + return 0; + +err_phy_connect: + phylink_destroy(dp->pl); + return err; +} + int dsa_port_link_register_of(struct dsa_port *dp) { + struct dsa_switch *ds = dp->ds; + + if (!ds->ops->adjust_link) + return dsa_port_phylink_register(dp); + + dev_warn(ds->dev, + "Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n"); + if (of_phy_is_fixed_link(dp->dn)) return dsa_port_fixed_link_register_of(dp); else @@ -609,6 +656,16 @@ int dsa_port_link_register_of(struct dsa_port *dp) void dsa_port_link_unregister_of(struct dsa_port *dp) { + struct dsa_switch *ds = dp->ds; + + if (!ds->ops->adjust_link) { + rtnl_lock(); + phylink_disconnect_phy(dp->pl); + rtnl_unlock(); + phylink_destroy(dp->pl); + return; + } + if (of_phy_is_fixed_link(dp->dn)) of_phy_deregister_fixed_link(dp->dn); else |