Commit 54186b91 authored by Andrew Lunn's avatar Andrew Lunn Committed by David S. Miller

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: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 78b39066
...@@ -524,7 +524,7 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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 = { ...@@ -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 = { ...@@ -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 { ...@@ -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, ...@@ -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, &reg);
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, ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment