summaryrefslogtreecommitdiffstats
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-02-21 13:02:42 +0000
commit6c98086622f0da655c81b5b42f1cf5d31396756b (patch)
tree3a1c6ab63cba7a71fa18c1afcc8efe44df9f9f3d
parente15310f506e1600e7a40be4056efe9cb2afc673c (diff)
net: phylink/dsa: fix DSA and CPU linkszii
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c51
-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, 31 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 3bf37c63c8cc..c2909a8af770 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -425,37 +425,18 @@ 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)
@@ -556,6 +537,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)
@@ -2523,16 +2517,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;
@@ -5476,6 +5464,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 179b1ddbfcae..c6daf644e995 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1069,6 +1069,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 e509e0ccba0c..960200fb2913 100644
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -81,6 +81,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 ad1681f80b6f..9d93afdf41e2 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -401,6 +401,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 0ecf4ce21126..1ce685af15e1 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -439,6 +439,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);
+}
+
void dsa_port_phylink_validate(struct phylink_config *config,
unsigned long *supported,
struct phylink_link_state *state)
@@ -549,6 +565,7 @@ void dsa_port_phylink_mac_link_up(struct phylink_config *config,
EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_up);
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,