net: dsa: mv88e6xxx: add phylink support
authorRussell King <rmk+kernel@armlinux.org.uk>
Thu, 9 Aug 2018 13:38:39 +0000 (15:38 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 9 Aug 2018 18:08:19 +0000 (11:08 -0700)
Add rudimentary phylink support to mv88e6xxx.

TODO:
- needs to call phylink_mac_change() when the port link comes up/goes down.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/mv88e6xxx/chip.h
drivers/net/dsa/mv88e6xxx/port.c
drivers/net/dsa/mv88e6xxx/port.h

index f7522d001365423a6d3d32cc60cd23cb0fbc6de7..1427541df31688eaeec2b5aa6b6ea3c5e5a9db2f 100644 (file)
@@ -598,10 +598,92 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
                dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
 }
 
+static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
+                                      unsigned long *mask,
+                                      struct phylink_link_state *state)
+{
+       if (!phy_interface_mode_is_8023z(state->interface)) {
+               /* 10M and 100M are only supported in non-802.3z mode */
+               phylink_set(mask, 10baseT_Half);
+               phylink_set(mask, 10baseT_Full);
+               phylink_set(mask, 100baseT_Half);
+               phylink_set(mask, 100baseT_Full);
+       }
+}
+
+static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port,
+                                      unsigned long *mask,
+                                      struct phylink_link_state *state)
+{
+       /* FIXME: if the port is in 1000Base-X mode, then it only supports
+        * 1000M FD speeds.  In this case, CMODE will indicate 5.
+        */
+       phylink_set(mask, 1000baseT_Full);
+       phylink_set(mask, 1000baseX_Full);
+
+       mv88e6065_phylink_validate(chip, port, mask, state);
+}
+
+static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port,
+                                      unsigned long *mask,
+                                      struct phylink_link_state *state)
+{
+       /* No ethtool bits for 200Mbps */
+       phylink_set(mask, 1000baseT_Full);
+       phylink_set(mask, 1000baseX_Full);
+
+       mv88e6065_phylink_validate(chip, port, mask, state);
+}
+
+static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port,
+                                      unsigned long *mask,
+                                      struct phylink_link_state *state)
+{
+       if (port >= 9)
+               phylink_set(mask, 2500baseX_Full);
+
+       /* No ethtool bits for 200Mbps */
+       phylink_set(mask, 1000baseT_Full);
+       phylink_set(mask, 1000baseX_Full);
+
+       mv88e6065_phylink_validate(chip, port, mask, state);
+}
+
+static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
+                                       unsigned long *mask,
+                                       struct phylink_link_state *state)
+{
+       if (port >= 9) {
+               phylink_set(mask, 10000baseT_Full);
+               phylink_set(mask, 10000baseKR_Full);
+       }
+
+       mv88e6390_phylink_validate(chip, port, mask, state);
+}
+
 static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
                               unsigned long *supported,
                               struct phylink_link_state *state)
 {
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+       struct mv88e6xxx_chip *chip = ds->priv;
+
+       /* Allow all the expected bits */
+       phylink_set(mask, Autoneg);
+       phylink_set(mask, Pause);
+       phylink_set_port_modes(mask);
+
+       if (chip->info->ops->phylink_validate)
+               chip->info->ops->phylink_validate(chip, port, mask, state);
+
+       bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
+       bitmap_and(state->advertising, state->advertising, mask,
+                  __ETHTOOL_LINK_MODE_MASK_NBITS);
+
+       /* We can only operate at 2500BaseX or 1000BaseX.  If requested
+        * to advertise both, only report advertising at 2500BaseX.
+        */
+       phylink_helper_basex_speed(state);
 }
 
 static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
@@ -611,7 +693,10 @@ static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
        int err;
 
        mutex_lock(&chip->reg_lock);
-       err = mv88e6xxx_port_link_state(chip, port, state);
+       if (chip->info->ops->port_link_state)
+               err = chip->info->ops->port_link_state(chip, port, state);
+       else
+               err = -EOPNOTSUPP;
        mutex_unlock(&chip->reg_lock);
 
        return err;
@@ -2611,6 +2696,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2627,6 +2713,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
        .rmu_disable = mv88e6085_g1_rmu_disable,
        .vtu_getnext = mv88e6352_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -2642,6 +2729,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
        .port_set_frame_mode = mv88e6085_port_set_frame_mode,
        .port_set_egress_floods = mv88e6185_port_set_egress_floods,
        .port_set_upstream_port = mv88e6095_port_set_upstream_port,
+       .port_link_state = mv88e6185_port_link_state,
        .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2653,6 +2741,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
        .reset = mv88e6185_g1_reset,
        .vtu_getnext = mv88e6185_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6097_ops = {
@@ -2675,6 +2764,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2689,6 +2779,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
        .rmu_disable = mv88e6085_g1_rmu_disable,
        .vtu_getnext = mv88e6352_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -2706,6 +2797,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
        .port_set_egress_floods = mv88e6352_port_set_egress_floods,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2719,6 +2811,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
        .reset = mv88e6352_g1_reset,
        .vtu_getnext = mv88e6352_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -2740,6 +2833,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
        .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_set_pause = mv88e6185_port_set_pause,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2755,6 +2849,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
        .reset = mv88e6185_g1_reset,
        .vtu_getnext = mv88e6185_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6141_ops = {
@@ -2780,6 +2875,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6390_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -2795,6 +2891,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
        .serdes_power = mv88e6341_serdes_power,
        .gpio_ops = &mv88e6352_gpio_ops,
+       .phylink_validate = mv88e6390_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -2817,6 +2914,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2832,6 +2930,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
        .avb_ops = &mv88e6165_avb_ops,
        .ptp_ops = &mv88e6165_ptp_ops,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -2847,6 +2946,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
        .port_set_speed = mv88e6185_port_set_speed,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2862,6 +2962,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
        .avb_ops = &mv88e6165_avb_ops,
        .ptp_ops = &mv88e6165_ptp_ops,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -2885,6 +2986,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2898,6 +3000,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
        .reset = mv88e6352_g1_reset,
        .vtu_getnext = mv88e6352_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -2923,6 +3026,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2939,6 +3043,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
        .serdes_power = mv88e6352_serdes_power,
        .gpio_ops = &mv88e6352_gpio_ops,
+       .phylink_validate = mv88e6352_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -2962,6 +3067,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -2975,6 +3081,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
        .reset = mv88e6352_g1_reset,
        .vtu_getnext = mv88e6352_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -3000,6 +3107,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -3016,6 +3124,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
        .serdes_power = mv88e6352_serdes_power,
        .gpio_ops = &mv88e6352_gpio_ops,
+       .phylink_validate = mv88e6352_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -3033,6 +3142,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
        .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
        .port_set_upstream_port = mv88e6095_port_set_upstream_port,
        .port_set_pause = mv88e6185_port_set_pause,
+       .port_link_state = mv88e6185_port_link_state,
        .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -3048,6 +3158,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
        .reset = mv88e6185_g1_reset,
        .vtu_getnext = mv88e6185_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6190_ops = {
@@ -3069,6 +3180,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
        .port_pause_limit = mv88e6390_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6390_g1_stats_snapshot,
        .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3085,6 +3197,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
        .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
        .serdes_power = mv88e6390_serdes_power,
        .gpio_ops = &mv88e6352_gpio_ops,
+       .phylink_validate = mv88e6390_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6190x_ops = {
@@ -3106,6 +3219,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
        .port_pause_limit = mv88e6390_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6390_g1_stats_snapshot,
        .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3122,6 +3236,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
        .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
        .serdes_power = mv88e6390_serdes_power,
        .gpio_ops = &mv88e6352_gpio_ops,
+       .phylink_validate = mv88e6390x_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6191_ops = {
@@ -3143,6 +3258,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
        .port_pause_limit = mv88e6390_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6390_g1_stats_snapshot,
        .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3160,6 +3276,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
        .serdes_power = mv88e6390_serdes_power,
        .avb_ops = &mv88e6390_avb_ops,
        .ptp_ops = &mv88e6352_ptp_ops,
+       .phylink_validate = mv88e6390_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3185,6 +3302,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -3203,6 +3321,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
        .gpio_ops = &mv88e6352_gpio_ops,
        .avb_ops = &mv88e6352_avb_ops,
        .ptp_ops = &mv88e6352_ptp_ops,
+       .phylink_validate = mv88e6352_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -3225,6 +3344,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
        .port_set_cmode = mv88e6390x_port_set_cmode,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6390_g1_stats_snapshot,
        .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3243,6 +3363,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
        .gpio_ops = &mv88e6352_gpio_ops,
        .avb_ops = &mv88e6390_avb_ops,
        .ptp_ops = &mv88e6352_ptp_ops,
+       .phylink_validate = mv88e6390_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3267,6 +3388,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3282,6 +3404,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
        .gpio_ops = &mv88e6352_gpio_ops,
        .avb_ops = &mv88e6352_avb_ops,
        .ptp_ops = &mv88e6352_ptp_ops,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3306,6 +3429,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3319,6 +3443,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
        .gpio_ops = &mv88e6352_gpio_ops,
        .avb_ops = &mv88e6352_avb_ops,
        .ptp_ops = &mv88e6352_ptp_ops,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6341_ops = {
@@ -3344,6 +3469,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6390_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3361,6 +3487,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
        .gpio_ops = &mv88e6352_gpio_ops,
        .avb_ops = &mv88e6390_avb_ops,
        .ptp_ops = &mv88e6352_ptp_ops,
+       .phylink_validate = mv88e6390_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3384,6 +3511,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -3397,6 +3525,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
        .reset = mv88e6352_g1_reset,
        .vtu_getnext = mv88e6352_g1_vtu_getnext,
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -3420,6 +3549,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -3435,6 +3565,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
        .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
        .avb_ops = &mv88e6352_avb_ops,
        .ptp_ops = &mv88e6352_ptp_ops,
+       .phylink_validate = mv88e6185_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3460,6 +3591,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
        .port_pause_limit = mv88e6097_port_pause_limit,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6320_g1_stats_snapshot,
        .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6095_stats_get_sset_count,
@@ -3481,6 +3613,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
        .serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
        .serdes_get_strings = mv88e6352_serdes_get_strings,
        .serdes_get_stats = mv88e6352_serdes_get_stats,
+       .phylink_validate = mv88e6352_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -3505,6 +3638,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
        .port_set_cmode = mv88e6390x_port_set_cmode,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6390_g1_stats_snapshot,
        .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3523,6 +3657,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
        .gpio_ops = &mv88e6352_gpio_ops,
        .avb_ops = &mv88e6390_avb_ops,
        .ptp_ops = &mv88e6352_ptp_ops,
+       .phylink_validate = mv88e6390_phylink_validate,
 };
 
 static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3547,6 +3682,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
        .port_set_cmode = mv88e6390x_port_set_cmode,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_link_state = mv88e6352_port_link_state,
        .stats_snapshot = mv88e6390_g1_stats_snapshot,
        .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
        .stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3565,6 +3701,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
        .gpio_ops = &mv88e6352_gpio_ops,
        .avb_ops = &mv88e6390_avb_ops,
        .ptp_ops = &mv88e6352_ptp_ops,
+       .phylink_validate = mv88e6390x_phylink_validate,
 };
 
 static const struct mv88e6xxx_info mv88e6xxx_table[] = {
index 92ebfd27116832493afcb2aade28cede89453d6c..cdc028fcdf964d2b5a325f3feae7e09022c0bd42 100644 (file)
@@ -396,6 +396,9 @@ struct mv88e6xxx_ops {
         */
        int (*port_set_upstream_port)(struct mv88e6xxx_chip *chip, int port,
                                      int upstream_port);
+       /* Return the port link state, as required by phylink */
+       int (*port_link_state)(struct mv88e6xxx_chip *chip, int port,
+                              struct phylink_link_state *state);
 
        /* Snapshot the statistics for a port. The statistics can then
         * be read back a leisure but still with a consistent view.
@@ -451,6 +454,11 @@ struct mv88e6xxx_ops {
 
        /* Precision Time Protocol operations */
        const struct mv88e6xxx_ptp_ops *ptp_ops;
+
+       /* Phylink */
+       void (*phylink_validate)(struct mv88e6xxx_chip *chip, int port,
+                                unsigned long *mask,
+                                struct phylink_link_state *state);
 };
 
 struct mv88e6xxx_irq_ops {
index c0701deaca6a6f2a9bb35cedfd48f0d0f2ecd1f1..2ff370cb2f3c5e96df318f816f81dbc90ede8935 100644 (file)
@@ -388,6 +388,19 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
        return 0;
 }
 
+/* mv88e6185 only has 3 bits for CMODE */
+static int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port)
+{
+       int err;
+       u16 reg;
+
+       err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
+       if (err)
+               return err;
+
+       return reg & MV88E6185_PORT_STS_CMODE_MASK;
+}
+
 int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
 {
        int err;
@@ -402,7 +415,7 @@ int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
        return 0;
 }
 
-int mv88e6xxx_port_link_state(struct mv88e6xxx_chip *chip, int port,
+int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
                              struct phylink_link_state *state)
 {
        int err;
@@ -423,7 +436,7 @@ int mv88e6xxx_port_link_state(struct mv88e6xxx_chip *chip, int port,
                state->speed = SPEED_1000;
                break;
        case MV88E6XXX_PORT_STS_SPEED_10000:
-               if ((reg &MV88E6XXX_PORT_STS_CMODE_MASK) ==
+               if ((reg & MV88E6XXX_PORT_STS_CMODE_MASK) ==
                    MV88E6XXX_PORT_STS_CMODE_2500BASEX)
                        state->speed = SPEED_2500;
                else
@@ -440,6 +453,45 @@ int mv88e6xxx_port_link_state(struct mv88e6xxx_chip *chip, int port,
        return 0;
 }
 
+int mv88e6185_port_link_state(struct mv88e6xxx_chip *chip, int port,
+                             struct phylink_link_state *state)
+{
+       if (state->interface == PHY_INTERFACE_MODE_1000BASEX) {
+               int cmode = mv88e6185_port_get_cmode(chip, port);
+
+               if (cmode < 0)
+                       return cmode;
+
+               /* When a port is in "Cross-chip serdes" mode, it uses
+                * 1000Base-X full duplex mode, but there is no automatic
+                * link detection. Use the sync OK status for link (as it
+                * would do for 1000Base-X mode.)
+                */
+               if (cmode == MV88E6185_PORT_STS_CMODE_SERDES) {
+                       u16 mac;
+                       int err;
+
+                       err = mv88e6xxx_port_read(chip, port,
+                                                 MV88E6XXX_PORT_MAC_CTL, &mac);
+                       if (err)
+                               return err;
+
+                       state->link = !!(mac & MV88E6185_PORT_MAC_CTL_SYNC_OK);
+                       state->an_enabled = 1;
+                       state->an_complete =
+                               !!(mac & MV88E6185_PORT_MAC_CTL_AN_DONE);
+                       state->duplex =
+                               state->link ? DUPLEX_FULL : DUPLEX_UNKNOWN;
+                       state->speed =
+                               state->link ? SPEED_1000 : SPEED_UNKNOWN;
+
+                       return 0;
+               }
+       }
+
+       return mv88e6352_port_link_state(chip, port, state);
+}
+
 /* Offset 0x02: Jamming Control
  *
  * Do not limit the period of time that this port can be paused for by
index 44916251567b202e759ff8a0eecd7e054b19eea0..9b8d2b229907635692c2f26ed21e4e637d04b999 100644 (file)
 #define MV88E6XXX_PORT_STS_CMODE_2500BASEX     0x000b
 #define MV88E6XXX_PORT_STS_CMODE_XAUI          0x000c
 #define MV88E6XXX_PORT_STS_CMODE_RXAUI         0x000d
+#define MV88E6185_PORT_STS_CDUPLEX             0x0008
+#define MV88E6185_PORT_STS_CMODE_MASK          0x0007
+#define MV88E6185_PORT_STS_CMODE_GMII_FD       0x0000
+#define MV88E6185_PORT_STS_CMODE_MII_100_FD_PS 0x0001
+#define MV88E6185_PORT_STS_CMODE_MII_100       0x0002
+#define MV88E6185_PORT_STS_CMODE_MII_10                0x0003
+#define MV88E6185_PORT_STS_CMODE_SERDES                0x0004
+#define MV88E6185_PORT_STS_CMODE_1000BASE_X    0x0005
+#define MV88E6185_PORT_STS_CMODE_PHY           0x0006
+#define MV88E6185_PORT_STS_CMODE_DISABLED      0x0007
 
 /* Offset 0x01: MAC (or PCS or Physical) Control Register */
 #define MV88E6XXX_PORT_MAC_CTL                         0x01
 #define MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK       0x8000
 #define MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK       0x4000
+#define MV88E6185_PORT_MAC_CTL_SYNC_OK                 0x4000
 #define MV88E6390_PORT_MAC_CTL_FORCE_SPEED             0x2000
 #define MV88E6390_PORT_MAC_CTL_ALTSPEED                        0x1000
 #define MV88E6352_PORT_MAC_CTL_200BASE                 0x1000
+#define MV88E6185_PORT_MAC_CTL_AN_EN                   0x0400
+#define MV88E6185_PORT_MAC_CTL_AN_RESTART              0x0200
+#define MV88E6185_PORT_MAC_CTL_AN_DONE                 0x0100
 #define MV88E6XXX_PORT_MAC_CTL_FC                      0x0080
 #define MV88E6XXX_PORT_MAC_CTL_FORCE_FC                        0x0040
 #define MV88E6XXX_PORT_MAC_CTL_LINK_UP                 0x0020
@@ -298,7 +312,9 @@ int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
 int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
                              phy_interface_t mode);
 int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
-int mv88e6xxx_port_link_state(struct mv88e6xxx_chip *chip, int port,
+int mv88e6185_port_link_state(struct mv88e6xxx_chip *chip, int port,
+                             struct phylink_link_state *state);
+int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
                              struct phylink_link_state *state);
 int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
 int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,