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-06-29 01:20:12 +0100
commit210af4d561ba5ab79999b14471edd4aeed98de5c (patch)
tree81a076ac204d27e4bfdcb869a9b44279610875b0
parentfef07e768c1e1dfe704c5e9bec0ef7a59f1d494b (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 b81257e42aec..b8308b210d70 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)
@@ -2547,16 +2544,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;
@@ -5538,6 +5529,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 56b06a95a727..dd6e9d5f6f0a 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1180,6 +1180,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 6a948f5be099..f1ace015bac2 100644
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -87,6 +87,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 62445442b091..a50d5007fd39 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -420,6 +420,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 ebd2b805680d..461d437d2da4 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -452,6 +452,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)
@@ -557,6 +573,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,