mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
Merge branch 'More-complete-PHYLINK-support-for-mv88e6xxx'
Andrew Lunn says: ==================== More complete PHYLINK support for mv88e6xxx Previous patches added sufficient PHYLINK support to the mv88e6xxx that it did not break existing use cases, basically fixed-link phys. This patchset builds out the support so that SFP modules, up to 2.5Gbps can be supported, on mv88e6390X, on ports 9 and 10. It also provides a framework which can be extended to support SFPs on ports 2-8 of mv88e6390X, 10Gbps PHYs, and SFP support on the 6352 family. Russell King did much of the initial work, implementing the validate and mac_link_state calls. However, there is an important TODO in the commit message: needs to call phylink_mac_change() when the port link comes up/goes down. The remaining patches implement this, by adding more support for the SERDES interfaces, in particular, interrupt support so we get notified when the SERDES gains/looses sync. This has been tested on the ZII devel C, using a Clearfog as peer device. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
ff50eda44d
@ -524,7 +524,7 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
|
||||
}
|
||||
|
||||
static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
|
||||
int link, int speed, int duplex,
|
||||
int link, int speed, int duplex, int pause,
|
||||
phy_interface_t mode)
|
||||
{
|
||||
int err;
|
||||
@ -543,6 +543,12 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
|
||||
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;
|
||||
}
|
||||
|
||||
if (chip->info->ops->port_set_duplex) {
|
||||
err = chip->info->ops->port_set_duplex(chip, port, duplex);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
@ -584,17 +590,100 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
|
||||
|
||||
mutex_lock(&chip->reg_lock);
|
||||
err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
|
||||
phydev->duplex, phydev->interface);
|
||||
phydev->duplex, phydev->pause,
|
||||
phydev->interface);
|
||||
mutex_unlock(&chip->reg_lock);
|
||||
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
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,
|
||||
@ -604,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;
|
||||
@ -615,7 +707,7 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
struct mv88e6xxx_chip *chip = ds->priv;
|
||||
int speed, duplex, link, err;
|
||||
int speed, duplex, link, pause, err;
|
||||
|
||||
if (mode == MLO_AN_PHY)
|
||||
return;
|
||||
@ -629,9 +721,10 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
|
||||
duplex = DUPLEX_UNFORCED;
|
||||
link = LINK_UNFORCED;
|
||||
}
|
||||
pause = !!phylink_test(state->advertising, Pause);
|
||||
|
||||
mutex_lock(&chip->reg_lock);
|
||||
err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex,
|
||||
err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause,
|
||||
state->interface);
|
||||
mutex_unlock(&chip->reg_lock);
|
||||
|
||||
@ -2080,6 +2173,9 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
|
||||
int err;
|
||||
u16 reg;
|
||||
|
||||
chip->ports[port].chip = chip;
|
||||
chip->ports[port].port = port;
|
||||
|
||||
/* MAC Forcing register: don't force link, speed, duplex or flow control
|
||||
* state to any particular values on physical ports, but force the CPU
|
||||
* port and all DSA ports to their maximum bandwidth and full duplex.
|
||||
@ -2087,10 +2183,12 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
|
||||
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);
|
||||
if (err)
|
||||
return err;
|
||||
@ -2239,7 +2337,12 @@ static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
|
||||
int err;
|
||||
|
||||
mutex_lock(&chip->reg_lock);
|
||||
|
||||
err = mv88e6xxx_serdes_power(chip, port, true);
|
||||
|
||||
if (!err && chip->info->ops->serdes_irq_setup)
|
||||
err = chip->info->ops->serdes_irq_setup(chip, port);
|
||||
|
||||
mutex_unlock(&chip->reg_lock);
|
||||
|
||||
return err;
|
||||
@ -2251,8 +2354,13 @@ static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port,
|
||||
struct mv88e6xxx_chip *chip = ds->priv;
|
||||
|
||||
mutex_lock(&chip->reg_lock);
|
||||
|
||||
if (chip->info->ops->serdes_irq_free)
|
||||
chip->info->ops->serdes_irq_free(chip, port);
|
||||
|
||||
if (mv88e6xxx_serdes_power(chip, port, false))
|
||||
dev_err(chip->dev, "failed to power off SERDES\n");
|
||||
|
||||
mutex_unlock(&chip->reg_lock);
|
||||
}
|
||||
|
||||
@ -2286,6 +2394,7 @@ static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
|
||||
static int mv88e6xxx_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_chip *chip = ds->priv;
|
||||
u8 cmode;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
@ -2294,6 +2403,17 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
|
||||
|
||||
mutex_lock(&chip->reg_lock);
|
||||
|
||||
/* Cache the cmode of each port. */
|
||||
for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
|
||||
if (chip->info->ops->port_get_cmode) {
|
||||
err = chip->info->ops->port_get_cmode(chip, i, &cmode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
chip->ports[i].cmode = cmode;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup Switch Port Registers */
|
||||
for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
|
||||
if (dsa_is_unused_port(ds, i))
|
||||
@ -2601,6 +2721,8 @@ 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,
|
||||
.port_get_cmode = mv88e6185_port_get_cmode,
|
||||
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2617,6 +2739,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 = {
|
||||
@ -2632,6 +2755,8 @@ 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,
|
||||
.port_get_cmode = mv88e6185_port_get_cmode,
|
||||
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2643,6 +2768,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 = {
|
||||
@ -2665,6 +2791,8 @@ 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,
|
||||
.port_get_cmode = mv88e6185_port_get_cmode,
|
||||
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2679,6 +2807,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 = {
|
||||
@ -2696,6 +2825,8 @@ 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,
|
||||
.port_get_cmode = mv88e6185_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2709,6 +2840,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 = {
|
||||
@ -2729,6 +2861,9 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
|
||||
.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
|
||||
.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,
|
||||
.port_get_cmode = mv88e6185_port_get_cmode,
|
||||
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2744,6 +2879,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 = {
|
||||
@ -2769,6 +2905,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6390_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -2784,6 +2922,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 = {
|
||||
@ -2806,6 +2945,8 @@ 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,
|
||||
.port_get_cmode = mv88e6185_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2821,6 +2962,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 = {
|
||||
@ -2836,6 +2978,8 @@ 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,
|
||||
.port_get_cmode = mv88e6185_port_get_cmode,
|
||||
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2851,6 +2995,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 = {
|
||||
@ -2874,6 +3019,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2887,6 +3034,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 = {
|
||||
@ -2912,6 +3060,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2928,6 +3078,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 = {
|
||||
@ -2951,6 +3102,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -2964,6 +3117,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 = {
|
||||
@ -2989,6 +3143,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -3005,6 +3161,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 = {
|
||||
@ -3021,6 +3178,9 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
|
||||
.port_set_egress_floods = mv88e6185_port_set_egress_floods,
|
||||
.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,
|
||||
.port_get_cmode = mv88e6185_port_get_cmode,
|
||||
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -3036,6 +3196,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 = {
|
||||
@ -3057,6 +3218,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6390_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -3072,7 +3235,10 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
|
||||
.vtu_getnext = mv88e6390_g1_vtu_getnext,
|
||||
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
|
||||
.serdes_power = mv88e6390_serdes_power,
|
||||
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
|
||||
.serdes_irq_free = mv88e6390_serdes_irq_free,
|
||||
.gpio_ops = &mv88e6352_gpio_ops,
|
||||
.phylink_validate = mv88e6390_phylink_validate,
|
||||
};
|
||||
|
||||
static const struct mv88e6xxx_ops mv88e6190x_ops = {
|
||||
@ -3094,6 +3260,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6390_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -3108,8 +3276,11 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
|
||||
.rmu_disable = mv88e6390_g1_rmu_disable,
|
||||
.vtu_getnext = mv88e6390_g1_vtu_getnext,
|
||||
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
|
||||
.serdes_power = mv88e6390_serdes_power,
|
||||
.serdes_power = mv88e6390x_serdes_power,
|
||||
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
|
||||
.serdes_irq_free = mv88e6390_serdes_irq_free,
|
||||
.gpio_ops = &mv88e6352_gpio_ops,
|
||||
.phylink_validate = mv88e6390x_phylink_validate,
|
||||
};
|
||||
|
||||
static const struct mv88e6xxx_ops mv88e6191_ops = {
|
||||
@ -3131,6 +3302,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6390_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -3146,8 +3319,11 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
|
||||
.vtu_getnext = mv88e6390_g1_vtu_getnext,
|
||||
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
|
||||
.serdes_power = mv88e6390_serdes_power,
|
||||
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
|
||||
.serdes_irq_free = mv88e6390_serdes_irq_free,
|
||||
.avb_ops = &mv88e6390_avb_ops,
|
||||
.ptp_ops = &mv88e6352_ptp_ops,
|
||||
.phylink_validate = mv88e6390_phylink_validate,
|
||||
};
|
||||
|
||||
static const struct mv88e6xxx_ops mv88e6240_ops = {
|
||||
@ -3173,6 +3349,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -3191,6 +3369,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 = {
|
||||
@ -3213,6 +3392,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6390_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -3228,9 +3409,12 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
|
||||
.vtu_getnext = mv88e6390_g1_vtu_getnext,
|
||||
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
|
||||
.serdes_power = mv88e6390_serdes_power,
|
||||
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
|
||||
.serdes_irq_free = mv88e6390_serdes_irq_free,
|
||||
.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 = {
|
||||
@ -3255,6 +3439,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -3270,6 +3456,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 = {
|
||||
@ -3294,6 +3481,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -3307,6 +3496,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 = {
|
||||
@ -3332,6 +3522,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6390_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -3349,6 +3541,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 = {
|
||||
@ -3372,6 +3565,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -3385,6 +3580,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 = {
|
||||
@ -3408,6 +3604,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -3423,6 +3621,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 = {
|
||||
@ -3448,6 +3647,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6320_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||
@ -3469,6 +3670,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 = {
|
||||
@ -3493,6 +3695,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6390_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -3508,9 +3712,12 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
|
||||
.vtu_getnext = mv88e6390_g1_vtu_getnext,
|
||||
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
|
||||
.serdes_power = mv88e6390_serdes_power,
|
||||
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
|
||||
.serdes_irq_free = mv88e6390_serdes_irq_free,
|
||||
.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 = {
|
||||
@ -3535,6 +3742,8 @@ 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,
|
||||
.port_get_cmode = mv88e6352_port_get_cmode,
|
||||
.stats_snapshot = mv88e6390_g1_stats_snapshot,
|
||||
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
|
||||
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
|
||||
@ -3549,10 +3758,13 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
|
||||
.rmu_disable = mv88e6390_g1_rmu_disable,
|
||||
.vtu_getnext = mv88e6390_g1_vtu_getnext,
|
||||
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
|
||||
.serdes_power = mv88e6390_serdes_power,
|
||||
.serdes_power = mv88e6390x_serdes_power,
|
||||
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
|
||||
.serdes_irq_free = mv88e6390_serdes_irq_free,
|
||||
.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[] = {
|
||||
|
@ -191,12 +191,16 @@ struct mv88e6xxx_port_hwtstamp {
|
||||
};
|
||||
|
||||
struct mv88e6xxx_port {
|
||||
struct mv88e6xxx_chip *chip;
|
||||
int port;
|
||||
u64 serdes_stats[2];
|
||||
u64 atu_member_violation;
|
||||
u64 atu_miss_violation;
|
||||
u64 atu_full_violation;
|
||||
u64 vtu_member_violation;
|
||||
u64 vtu_miss_violation;
|
||||
u8 cmode;
|
||||
int serdes_irq;
|
||||
};
|
||||
|
||||
struct mv88e6xxx_chip {
|
||||
@ -351,6 +355,13 @@ struct mv88e6xxx_ops {
|
||||
*/
|
||||
int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup);
|
||||
|
||||
#define PAUSE_ON 1
|
||||
#define PAUSE_OFF 0
|
||||
|
||||
/* Enable/disable sending Pause */
|
||||
int (*port_set_pause)(struct mv88e6xxx_chip *chip, int port,
|
||||
int pause);
|
||||
|
||||
#define SPEED_MAX INT_MAX
|
||||
#define SPEED_UNFORCED -2
|
||||
|
||||
@ -383,12 +394,16 @@ struct mv88e6xxx_ops {
|
||||
*/
|
||||
int (*port_set_cmode)(struct mv88e6xxx_chip *chip, int port,
|
||||
phy_interface_t mode);
|
||||
int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
|
||||
|
||||
/* Some devices have a per port register indicating what is
|
||||
* the upstream port this port should forward to.
|
||||
*/
|
||||
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.
|
||||
@ -420,6 +435,10 @@ struct mv88e6xxx_ops {
|
||||
/* Power on/off a SERDES interface */
|
||||
int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on);
|
||||
|
||||
/* SERDES interrupt handling */
|
||||
int (*serdes_irq_setup)(struct mv88e6xxx_chip *chip, int port);
|
||||
void (*serdes_irq_free)(struct mv88e6xxx_chip *chip, int port);
|
||||
|
||||
/* Statistics from the SERDES interface */
|
||||
int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port);
|
||||
int (*serdes_get_strings)(struct mv88e6xxx_chip *chip, int port,
|
||||
@ -444,6 +463,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 {
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "chip.h"
|
||||
#include "port.h"
|
||||
#include "serdes.h"
|
||||
|
||||
int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
|
||||
u16 *val)
|
||||
@ -36,6 +37,29 @@ int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
|
||||
return mv88e6xxx_write(chip, addr, reg, val);
|
||||
}
|
||||
|
||||
/* Offset 0x00: MAC (or PCS or Physical) Status Register
|
||||
*
|
||||
* For most devices, this is read only. However the 6185 has the MyPause
|
||||
* bit read/write.
|
||||
*/
|
||||
int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
|
||||
int pause)
|
||||
{
|
||||
u16 reg;
|
||||
int err;
|
||||
|
||||
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (pause)
|
||||
reg |= MV88E6XXX_PORT_STS_MY_PAUSE;
|
||||
else
|
||||
reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE;
|
||||
|
||||
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
|
||||
}
|
||||
|
||||
/* Offset 0x01: MAC (or PCS or Physical) Control Register
|
||||
*
|
||||
* Link, Duplex and Flow Control have one force bit, one value bit.
|
||||
@ -318,8 +342,9 @@ int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
|
||||
int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
|
||||
phy_interface_t mode)
|
||||
{
|
||||
u16 reg;
|
||||
int lane;
|
||||
u16 cmode;
|
||||
u16 reg;
|
||||
int err;
|
||||
|
||||
if (mode == PHY_INTERFACE_MODE_NA)
|
||||
@ -349,6 +374,20 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
|
||||
cmode = 0;
|
||||
}
|
||||
|
||||
lane = mv88e6390x_serdes_get_lane(chip, port);
|
||||
if (lane < 0)
|
||||
return lane;
|
||||
|
||||
if (chip->ports[port].serdes_irq) {
|
||||
err = mv88e6390_serdes_irq_disable(chip, port, lane);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mv88e6390_serdes_power(chip, port, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (cmode) {
|
||||
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);
|
||||
if (err)
|
||||
@ -360,12 +399,38 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
|
||||
err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mv88e6390_serdes_power(chip, port, true);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (chip->ports[port].serdes_irq) {
|
||||
err = mv88e6390_serdes_irq_enable(chip, port, lane);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
chip->ports[port].cmode = cmode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
|
||||
int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
|
||||
{
|
||||
int err;
|
||||
u16 reg;
|
||||
|
||||
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*cmode = reg & MV88E6185_PORT_STS_CMODE_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
|
||||
{
|
||||
int err;
|
||||
u16 reg;
|
||||
@ -379,7 +444,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;
|
||||
@ -400,7 +465,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
|
||||
@ -417,6 +482,42 @@ 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) {
|
||||
u8 cmode = chip->ports[port].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
|
||||
|
@ -42,14 +42,28 @@
|
||||
#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
|
||||
@ -242,6 +256,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
|
||||
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
|
||||
u16 val);
|
||||
|
||||
int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
|
||||
int pause);
|
||||
int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
|
||||
phy_interface_t mode);
|
||||
int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
|
||||
@ -295,8 +311,11 @@ int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
|
||||
u8 out);
|
||||
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_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
|
||||
int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
|
||||
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,
|
||||
|
@ -11,6 +11,8 @@
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mii.h>
|
||||
|
||||
#include "chip.h"
|
||||
@ -35,6 +37,22 @@ static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
|
||||
reg, val);
|
||||
}
|
||||
|
||||
static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip,
|
||||
int lane, int device, int reg, u16 *val)
|
||||
{
|
||||
int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
|
||||
|
||||
return mv88e6xxx_phy_read(chip, lane, reg_c45, val);
|
||||
}
|
||||
|
||||
static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
|
||||
int lane, int device, int reg, u16 val)
|
||||
{
|
||||
int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
|
||||
|
||||
return mv88e6xxx_phy_write(chip, lane, reg_c45, val);
|
||||
}
|
||||
|
||||
static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
|
||||
{
|
||||
u16 val, new_val;
|
||||
@ -57,14 +75,7 @@ static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
|
||||
|
||||
static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
|
||||
{
|
||||
u8 cmode;
|
||||
int err;
|
||||
|
||||
err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
|
||||
if (err) {
|
||||
dev_err(chip->dev, "failed to read cmode\n");
|
||||
return false;
|
||||
}
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
|
||||
if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASE_X) ||
|
||||
(cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) ||
|
||||
@ -174,16 +185,121 @@ int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
|
||||
return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
|
||||
}
|
||||
|
||||
/* Return the SERDES lane address a port is using. Only Ports 9 and 10
|
||||
* have SERDES lanes. Returns -ENODEV if a port does not have a lane.
|
||||
*/
|
||||
static int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
|
||||
{
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
|
||||
switch (port) {
|
||||
case 9:
|
||||
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
|
||||
return MV88E6390_PORT9_LANE0;
|
||||
return -ENODEV;
|
||||
case 10:
|
||||
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
|
||||
return MV88E6390_PORT10_LANE0;
|
||||
return -ENODEV;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the SERDES lane address a port is using. Ports 9 and 10 can
|
||||
* use multiple lanes. If so, return the first lane the port uses.
|
||||
* Returns -ENODEV if a port does not have a lane.
|
||||
*/
|
||||
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
|
||||
{
|
||||
u8 cmode_port9, cmode_port10, cmode_port;
|
||||
|
||||
cmode_port9 = chip->ports[9].cmode;
|
||||
cmode_port10 = chip->ports[10].cmode;
|
||||
cmode_port = chip->ports[port].cmode;
|
||||
|
||||
switch (port) {
|
||||
case 2:
|
||||
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT9_LANE1;
|
||||
return -ENODEV;
|
||||
case 3:
|
||||
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT9_LANE2;
|
||||
return -ENODEV;
|
||||
case 4:
|
||||
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT9_LANE3;
|
||||
return -ENODEV;
|
||||
case 5:
|
||||
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT10_LANE1;
|
||||
return -ENODEV;
|
||||
case 6:
|
||||
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT10_LANE2;
|
||||
return -ENODEV;
|
||||
case 7:
|
||||
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT10_LANE3;
|
||||
return -ENODEV;
|
||||
case 9:
|
||||
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
return MV88E6390_PORT9_LANE0;
|
||||
return -ENODEV;
|
||||
case 10:
|
||||
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
return MV88E6390_PORT10_LANE0;
|
||||
return -ENODEV;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
|
||||
static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on)
|
||||
static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane,
|
||||
bool on)
|
||||
{
|
||||
u16 val, new_val;
|
||||
int reg_c45;
|
||||
int err;
|
||||
|
||||
reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE |
|
||||
MV88E6390_PCS_CONTROL_1;
|
||||
err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val);
|
||||
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_PCS_CONTROL_1, &val);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -195,22 +311,21 @@ static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on)
|
||||
new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN;
|
||||
|
||||
if (val != new_val)
|
||||
err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val);
|
||||
err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_PCS_CONTROL_1, new_val);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
|
||||
static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr,
|
||||
bool on)
|
||||
/* Set the power on/off for SGMII and 1000Base-X */
|
||||
static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
|
||||
bool on)
|
||||
{
|
||||
u16 val, new_val;
|
||||
int reg_c45;
|
||||
int err;
|
||||
|
||||
reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE |
|
||||
MV88E6390_SGMII_CONTROL;
|
||||
err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val);
|
||||
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_SGMII_CONTROL, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -222,63 +337,25 @@ static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr,
|
||||
new_val = val | MV88E6390_SGMII_CONTROL_PDOWN;
|
||||
|
||||
if (val != new_val)
|
||||
err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val);
|
||||
err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_SGMII_CONTROL, new_val);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mv88e6390_serdes_lower(struct mv88e6xxx_chip *chip, u8 cmode,
|
||||
int port_donor, int lane, bool rxaui, bool on)
|
||||
static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port,
|
||||
int lane, bool on)
|
||||
{
|
||||
int err;
|
||||
u8 cmode_donor;
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
|
||||
err = mv88e6xxx_port_get_cmode(chip, port_donor, &cmode_donor);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (cmode_donor) {
|
||||
case MV88E6XXX_PORT_STS_CMODE_RXAUI:
|
||||
if (!rxaui)
|
||||
break;
|
||||
/* Fall through */
|
||||
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
|
||||
case MV88E6XXX_PORT_STS_CMODE_SGMII:
|
||||
case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
|
||||
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)
|
||||
return mv88e6390_serdes_sgmii(chip, lane, on);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6390_serdes_port9(struct mv88e6xxx_chip *chip, u8 cmode,
|
||||
bool on)
|
||||
{
|
||||
switch (cmode) {
|
||||
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
|
||||
case MV88E6XXX_PORT_STS_CMODE_SGMII:
|
||||
return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT9_LANE0, on);
|
||||
case MV88E6XXX_PORT_STS_CMODE_XAUI:
|
||||
case MV88E6XXX_PORT_STS_CMODE_RXAUI:
|
||||
case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
|
||||
return mv88e6390_serdes_10g(chip, MV88E6390_PORT9_LANE0, on);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6390_serdes_port10(struct mv88e6xxx_chip *chip, u8 cmode,
|
||||
bool on)
|
||||
{
|
||||
switch (cmode) {
|
||||
case MV88E6XXX_PORT_STS_CMODE_SGMII:
|
||||
return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT10_LANE0, on);
|
||||
case MV88E6XXX_PORT_STS_CMODE_XAUI:
|
||||
case MV88E6XXX_PORT_STS_CMODE_RXAUI:
|
||||
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
|
||||
case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
|
||||
return mv88e6390_serdes_10g(chip, MV88E6390_PORT10_LANE0, on);
|
||||
return mv88e6390_serdes_power_sgmii(chip, lane, on);
|
||||
case MV88E6XXX_PORT_STS_CMODE_XAUI:
|
||||
case MV88E6XXX_PORT_STS_CMODE_RXAUI:
|
||||
return mv88e6390_serdes_power_10g(chip, lane, on);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -286,63 +363,235 @@ static int mv88e6390_serdes_port10(struct mv88e6xxx_chip *chip, u8 cmode,
|
||||
|
||||
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
|
||||
{
|
||||
u8 cmode;
|
||||
int err;
|
||||
int lane;
|
||||
|
||||
err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
|
||||
if (err)
|
||||
return err;
|
||||
lane = mv88e6390_serdes_get_lane(chip, port);
|
||||
if (lane == -ENODEV)
|
||||
return 0;
|
||||
|
||||
if (lane < 0)
|
||||
return lane;
|
||||
|
||||
switch (port) {
|
||||
case 2:
|
||||
return mv88e6390_serdes_lower(chip, cmode, 9,
|
||||
MV88E6390_PORT9_LANE1,
|
||||
false, on);
|
||||
case 3:
|
||||
return mv88e6390_serdes_lower(chip, cmode, 9,
|
||||
MV88E6390_PORT9_LANE2,
|
||||
true, on);
|
||||
case 4:
|
||||
return mv88e6390_serdes_lower(chip, cmode, 9,
|
||||
MV88E6390_PORT9_LANE3,
|
||||
true, on);
|
||||
case 5:
|
||||
return mv88e6390_serdes_lower(chip, cmode, 10,
|
||||
MV88E6390_PORT10_LANE1,
|
||||
false, on);
|
||||
case 6:
|
||||
return mv88e6390_serdes_lower(chip, cmode, 10,
|
||||
MV88E6390_PORT10_LANE2,
|
||||
true, on);
|
||||
case 7:
|
||||
return mv88e6390_serdes_lower(chip, cmode, 10,
|
||||
MV88E6390_PORT10_LANE3,
|
||||
true, on);
|
||||
case 9:
|
||||
return mv88e6390_serdes_port9(chip, cmode, on);
|
||||
case 10:
|
||||
return mv88e6390_serdes_port10(chip, cmode, on);
|
||||
case 9 ... 10:
|
||||
return mv88e6390_serdes_power_lane(chip, port, lane, on);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
|
||||
int mv88e6390x_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
|
||||
{
|
||||
int lane;
|
||||
|
||||
lane = mv88e6390x_serdes_get_lane(chip, port);
|
||||
if (lane == -ENODEV)
|
||||
return 0;
|
||||
|
||||
if (lane < 0)
|
||||
return lane;
|
||||
|
||||
switch (port) {
|
||||
case 2 ... 4:
|
||||
case 5 ... 7:
|
||||
case 9 ... 10:
|
||||
return mv88e6390_serdes_power_lane(chip, port, lane, on);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
|
||||
int port, int lane)
|
||||
{
|
||||
struct dsa_switch *ds = chip->ds;
|
||||
u16 status;
|
||||
bool up;
|
||||
|
||||
mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_SGMII_STATUS, &status);
|
||||
|
||||
/* Status must be read twice in order to give the current link
|
||||
* status. Otherwise the change in link status since the last
|
||||
* read of the register is returned.
|
||||
*/
|
||||
mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_SGMII_STATUS, &status);
|
||||
up = status & MV88E6390_SGMII_STATUS_LINK;
|
||||
|
||||
dsa_port_phylink_mac_change(ds, port, up);
|
||||
}
|
||||
|
||||
static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
|
||||
int lane)
|
||||
{
|
||||
return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_SGMII_INT_ENABLE,
|
||||
MV88E6390_SGMII_INT_LINK_DOWN |
|
||||
MV88E6390_SGMII_INT_LINK_UP);
|
||||
}
|
||||
|
||||
static int mv88e6390_serdes_irq_disable_sgmii(struct mv88e6xxx_chip *chip,
|
||||
int lane)
|
||||
{
|
||||
return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_SGMII_INT_ENABLE, 0);
|
||||
}
|
||||
|
||||
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
|
||||
int lane)
|
||||
{
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
int err = 0;
|
||||
|
||||
switch (cmode) {
|
||||
case MV88E6XXX_PORT_STS_CMODE_SGMII:
|
||||
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
|
||||
case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
|
||||
err = mv88e6390_serdes_irq_enable_sgmii(chip, lane);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
|
||||
int lane)
|
||||
{
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
int err = 0;
|
||||
|
||||
switch (cmode) {
|
||||
case MV88E6XXX_PORT_STS_CMODE_SGMII:
|
||||
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
|
||||
case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
|
||||
err = mv88e6390_serdes_irq_disable_sgmii(chip, lane);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
|
||||
int lane, u16 *status)
|
||||
{
|
||||
int err;
|
||||
u8 cmode;
|
||||
|
||||
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_SGMII_INT_STATUS, status);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
|
||||
{
|
||||
struct mv88e6xxx_port *port = dev_id;
|
||||
struct mv88e6xxx_chip *chip = port->chip;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u8 cmode = port->cmode;
|
||||
u16 status;
|
||||
int lane;
|
||||
int err;
|
||||
|
||||
lane = mv88e6390x_serdes_get_lane(chip, port->port);
|
||||
|
||||
mutex_lock(&chip->reg_lock);
|
||||
|
||||
switch (cmode) {
|
||||
case MV88E6XXX_PORT_STS_CMODE_SGMII:
|
||||
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
|
||||
case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
|
||||
err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
|
||||
if (err)
|
||||
goto out;
|
||||
if (status && (MV88E6390_SGMII_INT_LINK_DOWN ||
|
||||
MV88E6390_SGMII_INT_LINK_UP)) {
|
||||
ret = IRQ_HANDLED;
|
||||
mv88e6390_serdes_irq_link_sgmii(chip, port->port, lane);
|
||||
}
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&chip->reg_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
|
||||
{
|
||||
int lane;
|
||||
int err;
|
||||
|
||||
/* Only support ports 9 and 10 at the moment */
|
||||
if (port < 9)
|
||||
return 0;
|
||||
|
||||
lane = mv88e6390x_serdes_get_lane(chip, port);
|
||||
|
||||
if (lane == -ENODEV)
|
||||
return 0;
|
||||
|
||||
if (lane < 0)
|
||||
return lane;
|
||||
|
||||
chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
|
||||
port);
|
||||
if (chip->ports[port].serdes_irq < 0) {
|
||||
dev_err(chip->dev, "Unable to map SERDES irq: %d\n",
|
||||
chip->ports[port].serdes_irq);
|
||||
return chip->ports[port].serdes_irq;
|
||||
}
|
||||
|
||||
/* Requesting the IRQ will trigger irq callbacks. So we cannot
|
||||
* hold the reg_lock.
|
||||
*/
|
||||
mutex_unlock(&chip->reg_lock);
|
||||
err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
|
||||
mv88e6390_serdes_thread_fn,
|
||||
IRQF_ONESHOT, "mv88e6xxx-serdes",
|
||||
&chip->ports[port]);
|
||||
mutex_lock(&chip->reg_lock);
|
||||
|
||||
if (err) {
|
||||
dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return mv88e6390_serdes_irq_enable(chip, port, lane);
|
||||
}
|
||||
|
||||
void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
|
||||
{
|
||||
int lane = mv88e6390x_serdes_get_lane(chip, port);
|
||||
|
||||
if (port < 9)
|
||||
return;
|
||||
|
||||
if (lane < 0)
|
||||
return;
|
||||
|
||||
mv88e6390_serdes_irq_disable(chip, port, lane);
|
||||
|
||||
/* Freeing the IRQ will trigger irq callbacks. So we cannot
|
||||
* hold the reg_lock.
|
||||
*/
|
||||
mutex_unlock(&chip->reg_lock);
|
||||
free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
|
||||
mutex_lock(&chip->reg_lock);
|
||||
|
||||
chip->ports[port].serdes_irq = 0;
|
||||
}
|
||||
|
||||
int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
|
||||
{
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
|
||||
if (port != 5)
|
||||
return 0;
|
||||
|
||||
err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
|
||||
return mv88e6390_serdes_sgmii(chip, MV88E6341_ADDR_SERDES, on);
|
||||
return mv88e6390_serdes_power_sgmii(chip, MV88E6341_ADDR_SERDES,
|
||||
on);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,7 +29,6 @@
|
||||
#define MV88E6390_PORT10_LANE1 0x15
|
||||
#define MV88E6390_PORT10_LANE2 0x16
|
||||
#define MV88E6390_PORT10_LANE3 0x17
|
||||
#define MV88E6390_SERDES_DEVICE (4 << 16)
|
||||
|
||||
/* 10GBASE-R and 10GBASE-X4/X2 */
|
||||
#define MV88E6390_PCS_CONTROL_1 0x1000
|
||||
@ -43,13 +42,36 @@
|
||||
#define MV88E6390_SGMII_CONTROL_RESET BIT(15)
|
||||
#define MV88E6390_SGMII_CONTROL_LOOPBACK BIT(14)
|
||||
#define MV88E6390_SGMII_CONTROL_PDOWN BIT(11)
|
||||
#define MV88E6390_SGMII_STATUS 0x2001
|
||||
#define MV88E6390_SGMII_STATUS_AN_DONE BIT(5)
|
||||
#define MV88E6390_SGMII_STATUS_REMOTE_FAULT BIT(4)
|
||||
#define MV88E6390_SGMII_STATUS_LINK BIT(2)
|
||||
#define MV88E6390_SGMII_INT_ENABLE 0xa001
|
||||
#define MV88E6390_SGMII_INT_SPEED_CHANGE BIT(14)
|
||||
#define MV88E6390_SGMII_INT_DUPLEX_CHANGE BIT(13)
|
||||
#define MV88E6390_SGMII_INT_PAGE_RX BIT(12)
|
||||
#define MV88E6390_SGMII_INT_AN_COMPLETE BIT(11)
|
||||
#define MV88E6390_SGMII_INT_LINK_DOWN BIT(10)
|
||||
#define MV88E6390_SGMII_INT_LINK_UP BIT(9)
|
||||
#define MV88E6390_SGMII_INT_SYMBOL_ERROR BIT(8)
|
||||
#define MV88E6390_SGMII_INT_FALSE_CARRIER BIT(7)
|
||||
#define MV88E6390_SGMII_INT_STATUS 0xa002
|
||||
|
||||
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
|
||||
int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
|
||||
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
|
||||
int mv88e6390x_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
|
||||
int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
|
||||
void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
|
||||
int port, uint8_t *data);
|
||||
int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
|
||||
uint64_t *data);
|
||||
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
|
||||
int lane);
|
||||
int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
|
||||
int lane);
|
||||
|
||||
#endif
|
||||
|
@ -1688,4 +1688,34 @@ static const struct sfp_upstream_ops sfp_phylink_ops = {
|
||||
.disconnect_phy = phylink_sfp_disconnect_phy,
|
||||
};
|
||||
|
||||
/* Helpers for MAC drivers */
|
||||
|
||||
/**
|
||||
* phylink_helper_basex_speed() - 1000BaseX/2500BaseX helper
|
||||
* @state: a pointer to a &struct phylink_link_state
|
||||
*
|
||||
* Inspect the interface mode, advertising mask or forced speed and
|
||||
* decide whether to run at 2.5Gbit or 1Gbit appropriately, switching
|
||||
* the interface mode to suit. @state->interface is appropriately
|
||||
* updated, and the advertising mask has the "other" baseX_Full flag
|
||||
* cleared.
|
||||
*/
|
||||
void phylink_helper_basex_speed(struct phylink_link_state *state)
|
||||
{
|
||||
if (phy_interface_mode_is_8023z(state->interface)) {
|
||||
bool want_2500 = state->an_enabled ?
|
||||
phylink_test(state->advertising, 2500baseX_Full) :
|
||||
state->speed == SPEED_2500;
|
||||
|
||||
if (want_2500) {
|
||||
phylink_clear(state->advertising, 1000baseX_Full);
|
||||
state->interface = PHY_INTERFACE_MODE_2500BASEX;
|
||||
} else {
|
||||
phylink_clear(state->advertising, 2500baseX_Full);
|
||||
state->interface = PHY_INTERFACE_MODE_1000BASEX;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phylink_helper_basex_speed);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -234,5 +234,6 @@ int phylink_mii_ioctl(struct phylink *, struct ifreq *, int);
|
||||
#define phylink_test(bm, mode) __phylink_do_bit(test_bit, bm, mode)
|
||||
|
||||
void phylink_set_port_modes(unsigned long *bits);
|
||||
void phylink_helper_basex_speed(struct phylink_link_state *state);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user