summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2020-02-17 16:23:31 +0000
committerRussell King <rmk+kernel@armlinux.org.uk>2020-10-12 21:52:16 +0100
commit6f85be7ce3fa31f378cda12c46b787dbfd1b6bc7 (patch)
tree6ecb87c8ba16faf7af2dc27af094aa3a83f0a73e
parentab2e5046153fad0d9be339e86ca3ae90f7e1dbc5 (diff)
net: phylink/dsa: fix DSA and CPU links
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c48
-rw-r--r--drivers/net/phy/phylink.c15
-rw-r--r--include/linux/phylink.h2
-rw-r--r--include/net/dsa.h2
-rw-r--r--net/dsa/port.c17
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,