net: dsa: mv88e6xxx: Add support to enabling pause
The 6185 can enable/disable 802.3z pause be setting the MyPause bit in the port status register. Add an op to support this. 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>
This commit is contained in:
parent
78b39066c4
commit
54186b91bd
|
@ -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,
|
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)
|
phy_interface_t mode)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -543,6 +543,12 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
|
||||||
goto restore_link;
|
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) {
|
if (chip->info->ops->port_set_duplex) {
|
||||||
err = chip->info->ops->port_set_duplex(chip, port, duplex);
|
err = chip->info->ops->port_set_duplex(chip, port, duplex);
|
||||||
if (err && err != -EOPNOTSUPP)
|
if (err && err != -EOPNOTSUPP)
|
||||||
|
@ -584,7 +590,8 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
|
||||||
|
|
||||||
mutex_lock(&chip->reg_lock);
|
mutex_lock(&chip->reg_lock);
|
||||||
err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
|
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);
|
mutex_unlock(&chip->reg_lock);
|
||||||
|
|
||||||
if (err && err != -EOPNOTSUPP)
|
if (err && err != -EOPNOTSUPP)
|
||||||
|
@ -615,7 +622,7 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
|
||||||
const struct phylink_link_state *state)
|
const struct phylink_link_state *state)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_chip *chip = ds->priv;
|
struct mv88e6xxx_chip *chip = ds->priv;
|
||||||
int speed, duplex, link, err;
|
int speed, duplex, link, pause, err;
|
||||||
|
|
||||||
if (mode == MLO_AN_PHY)
|
if (mode == MLO_AN_PHY)
|
||||||
return;
|
return;
|
||||||
|
@ -629,9 +636,10 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
|
||||||
duplex = DUPLEX_UNFORCED;
|
duplex = DUPLEX_UNFORCED;
|
||||||
link = LINK_UNFORCED;
|
link = LINK_UNFORCED;
|
||||||
}
|
}
|
||||||
|
pause = !!phylink_test(state->advertising, Pause);
|
||||||
|
|
||||||
mutex_lock(&chip->reg_lock);
|
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);
|
state->interface);
|
||||||
mutex_unlock(&chip->reg_lock);
|
mutex_unlock(&chip->reg_lock);
|
||||||
|
|
||||||
|
@ -2087,10 +2095,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))
|
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
|
||||||
err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
|
err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
|
||||||
SPEED_MAX, DUPLEX_FULL,
|
SPEED_MAX, DUPLEX_FULL,
|
||||||
|
PAUSE_OFF,
|
||||||
PHY_INTERFACE_MODE_NA);
|
PHY_INTERFACE_MODE_NA);
|
||||||
else
|
else
|
||||||
err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
|
err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
|
||||||
SPEED_UNFORCED, DUPLEX_UNFORCED,
|
SPEED_UNFORCED, DUPLEX_UNFORCED,
|
||||||
|
PAUSE_ON,
|
||||||
PHY_INTERFACE_MODE_NA);
|
PHY_INTERFACE_MODE_NA);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -2729,6 +2739,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
|
||||||
.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
|
.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
|
||||||
.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
|
.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
|
||||||
.port_pause_limit = mv88e6097_port_pause_limit,
|
.port_pause_limit = mv88e6097_port_pause_limit,
|
||||||
|
.port_set_pause = mv88e6185_port_set_pause,
|
||||||
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
||||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||||
|
@ -3021,6 +3032,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
|
||||||
.port_set_egress_floods = mv88e6185_port_set_egress_floods,
|
.port_set_egress_floods = mv88e6185_port_set_egress_floods,
|
||||||
.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
|
.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
|
||||||
.port_set_upstream_port = mv88e6095_port_set_upstream_port,
|
.port_set_upstream_port = mv88e6095_port_set_upstream_port,
|
||||||
|
.port_set_pause = mv88e6185_port_set_pause,
|
||||||
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
|
||||||
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
||||||
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
|
||||||
|
|
|
@ -351,6 +351,13 @@ struct mv88e6xxx_ops {
|
||||||
*/
|
*/
|
||||||
int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup);
|
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_MAX INT_MAX
|
||||||
#define SPEED_UNFORCED -2
|
#define SPEED_UNFORCED -2
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,29 @@ int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
|
||||||
return mv88e6xxx_write(chip, addr, reg, val);
|
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
|
/* Offset 0x01: MAC (or PCS or Physical) Control Register
|
||||||
*
|
*
|
||||||
* Link, Duplex and Flow Control have one force bit, one value bit.
|
* Link, Duplex and Flow Control have one force bit, one value bit.
|
||||||
|
|
|
@ -242,6 +242,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,
|
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
|
||||||
u16 val);
|
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,
|
int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
|
||||||
phy_interface_t mode);
|
phy_interface_t mode);
|
||||||
int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
|
int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
|
||||||
|
|
Loading…
Reference in New Issue