From 6f85be7ce3fa31f378cda12c46b787dbfd1b6bc7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 17 Feb 2020 16:23:31 +0000 Subject: net: phylink/dsa: fix DSA and CPU links Signed-off-by: Russell King --- drivers/net/dsa/mv88e6xxx/chip.c | 48 +++++++++++++++++----------------------- drivers/net/phy/phylink.c | 15 +++++++++++++ include/linux/phylink.h | 2 ++ include/net/dsa.h | 2 ++ net/dsa/port.c | 17 ++++++++++++++ 5 files changed, 56 insertions(+), 28 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index f392613f6373..543bd9cdd3ca 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -428,37 +428,21 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, if (!chip->info->ops->port_set_link) return 0; - if (speed = SPEED_MAX) { - if (chip->info->ops->port_max_speed_mode) - mode = chip->info->ops->port_max_speed_mode(port); - if (chip->info->ops->port_max_speed) - speed = chip->info->ops->port_max_speed(port); - } - /* Port's MAC control must not be changed unless the link is down */ err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); if (err) return err; - if (chip->info->ops->port_set_speed_duplex) { - err = chip->info->ops->port_set_speed_duplex(chip, port, - speed, duplex); - if (err && err != -EOPNOTSUPP) - goto restore_link; - } - if (chip->info->ops->port_set_pause) { err = chip->info->ops->port_set_pause(chip, port, pause); if (err) - goto restore_link; + return err; } - err = mv88e6xxx_port_config_interface(chip, port, mode); -restore_link: if (chip->info->ops->port_set_link(chip, port, link)) dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); - return err; + return 0; } static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) @@ -559,6 +543,19 @@ static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, return 0; } +static void mv88e6xxx_default_config(struct dsa_switch *ds, int port, + struct phylink_link_state *state) +{ + struct mv88e6xxx_chip *chip = ds->priv; + + if (chip->info->ops->port_max_speed_mode) + state->interface = chip->info->ops->port_max_speed_mode(port); + + state->duplex = DUPLEX_FULL; + state->speed = chip->info->ops->port_max_speed(port); + state->link = true; +} + static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, unsigned long *mask, struct phylink_link_state *state) @@ -2571,16 +2568,10 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) * state to any particular values on physical ports, but force the CPU * port and all DSA ports to their maximum bandwidth and full duplex. */ - if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) - err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, - SPEED_MAX, DUPLEX_FULL, - PAUSE_OFF, - PHY_INTERFACE_MODE_NA); - else - err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, - SPEED_UNFORCED, DUPLEX_UNFORCED, - PAUSE_ON, - PHY_INTERFACE_MODE_NA); + err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, + SPEED_UNFORCED, DUPLEX_UNFORCED, + PAUSE_ON, + PHY_INTERFACE_MODE_NA); if (err) return err; @@ -5597,6 +5588,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .get_tag_protocol = mv88e6xxx_get_tag_protocol, .setup = mv88e6xxx_setup, .teardown = mv88e6xxx_teardown, + .phylink_default_config = mv88e6xxx_default_config, .phylink_validate = mv88e6xxx_validate, .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state, .phylink_mac_config = mv88e6xxx_mac_config, diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 6680de39e338..a32eb56d48f3 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1188,6 +1188,21 @@ void phylink_start(struct phylink *pl) ASSERT_RTNL(); + /* + * If no PHY or SFP attached, and but we're in PHY mode, + * attempt to pick up a default configuration. + */ + if (pl->cfg_link_an_mode == MLO_AN_PHY && !pl->phydev && !pl->sfp_bus) { + if (pl->mac_ops->default_config) { + pl->mac_ops->default_config(pl->config, + &pl->link_config); + pl->cfg_link_an_mode = MLO_AN_FIXED; + pl->cur_link_an_mode = MLO_AN_FIXED; + } else { + phylink_warn(pl, "no default configuration\n"); + } + } + phylink_info(pl, "configuring for %s/%s link mode\n", phylink_an_mode_str(pl->cur_link_an_mode), phy_modes(pl->link_config.interface)); diff --git a/include/linux/phylink.h b/include/linux/phylink.h index f19cd028afb0..32794f90924b 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -91,6 +91,8 @@ struct phylink_config { * The individual methods are described more fully below. */ struct phylink_mac_ops { + void (*default_config)(struct phylink_config *config, + struct phylink_link_state *state); void (*validate)(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state); diff --git a/include/net/dsa.h b/include/net/dsa.h index 75c8fac82017..11f8875d34a1 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -438,6 +438,8 @@ struct dsa_switch_ops { /* * PHYLINK integration */ + void (*phylink_default_config)(struct dsa_switch *ds, int port, + struct phylink_link_state *state); void (*phylink_validate)(struct dsa_switch *ds, int port, unsigned long *supported, struct phylink_link_state *state); diff --git a/net/dsa/port.c b/net/dsa/port.c index 376d02373e59..2938a1b93d4f 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -485,6 +485,22 @@ static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp) return phydev; } +static void dsa_port_phylink_default_config(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; + + if (dp->type == DSA_PORT_TYPE_USER || + !ds->ops->phylink_default_config) { + dev_err(ds->dev, "p%d: improper configuration for port\n", + dp->index); + return; + } + + ds->ops->phylink_default_config(ds, dp->index, state); +} + static void dsa_port_phylink_validate(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state) @@ -590,6 +606,7 @@ static void dsa_port_phylink_mac_link_up(struct phylink_config *config, } const struct phylink_mac_ops dsa_port_phylink_mac_ops = { + .default_config = dsa_port_phylink_default_config, .validate = dsa_port_phylink_validate, .mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state, .mac_config = dsa_port_phylink_mac_config, -- cgit