diff options
author | Andrew Lunn <andrew@lunn.ch> | 2018-08-09 09:38:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-08-09 14:08:19 -0400 |
commit | 54186b91bde1711080d0b23ce25f0bee5a058fc9 (patch) | |
tree | ae6b23679f30ff4f141c42b77d76e1557d9463f0 | |
parent | 78b39066c425ce913af1c0353d8fdc5d8c416e32 (diff) |
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>
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 20 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.h | 7 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/port.c | 23 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/port.h | 2 |
4 files changed, 48 insertions, 4 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 0b5a2c31f395..f7522d001365 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c | |||
@@ -524,7 +524,7 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update) | |||
524 | } | 524 | } |
525 | 525 | ||
526 | static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, | 526 | static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, |
527 | int link, int speed, int duplex, | 527 | int link, int speed, int duplex, int pause, |
528 | phy_interface_t mode) | 528 | phy_interface_t mode) |
529 | { | 529 | { |
530 | int err; | 530 | int err; |
@@ -543,6 +543,12 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, | |||
543 | goto restore_link; | 543 | goto restore_link; |
544 | } | 544 | } |
545 | 545 | ||
546 | if (chip->info->ops->port_set_pause) { | ||
547 | err = chip->info->ops->port_set_pause(chip, port, pause); | ||
548 | if (err) | ||
549 | goto restore_link; | ||
550 | } | ||
551 | |||
546 | if (chip->info->ops->port_set_duplex) { | 552 | if (chip->info->ops->port_set_duplex) { |
547 | err = chip->info->ops->port_set_duplex(chip, port, duplex); | 553 | err = chip->info->ops->port_set_duplex(chip, port, duplex); |
548 | if (err && err != -EOPNOTSUPP) | 554 | if (err && err != -EOPNOTSUPP) |
@@ -584,7 +590,8 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, | |||
584 | 590 | ||
585 | mutex_lock(&chip->reg_lock); | 591 | mutex_lock(&chip->reg_lock); |
586 | err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed, | 592 | err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed, |
587 | phydev->duplex, phydev->interface); | 593 | phydev->duplex, phydev->pause, |
594 | phydev->interface); | ||
588 | mutex_unlock(&chip->reg_lock); | 595 | mutex_unlock(&chip->reg_lock); |
589 | 596 | ||
590 | if (err && err != -EOPNOTSUPP) | 597 | if (err && err != -EOPNOTSUPP) |
@@ -615,7 +622,7 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, | |||
615 | const struct phylink_link_state *state) | 622 | const struct phylink_link_state *state) |
616 | { | 623 | { |
617 | struct mv88e6xxx_chip *chip = ds->priv; | 624 | struct mv88e6xxx_chip *chip = ds->priv; |
618 | int speed, duplex, link, err; | 625 | int speed, duplex, link, pause, err; |
619 | 626 | ||
620 | if (mode == MLO_AN_PHY) | 627 | if (mode == MLO_AN_PHY) |
621 | return; | 628 | return; |
@@ -629,9 +636,10 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, | |||
629 | duplex = DUPLEX_UNFORCED; | 636 | duplex = DUPLEX_UNFORCED; |
630 | link = LINK_UNFORCED; | 637 | link = LINK_UNFORCED; |
631 | } | 638 | } |
639 | pause = !!phylink_test(state->advertising, Pause); | ||
632 | 640 | ||
633 | mutex_lock(&chip->reg_lock); | 641 | mutex_lock(&chip->reg_lock); |
634 | err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, | 642 | err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause, |
635 | state->interface); | 643 | state->interface); |
636 | mutex_unlock(&chip->reg_lock); | 644 | mutex_unlock(&chip->reg_lock); |
637 | 645 | ||
@@ -2087,10 +2095,12 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) | |||
2087 | if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) | 2095 | if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) |
2088 | err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, | 2096 | err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, |
2089 | SPEED_MAX, DUPLEX_FULL, | 2097 | SPEED_MAX, DUPLEX_FULL, |
2098 | PAUSE_OFF, | ||
2090 | PHY_INTERFACE_MODE_NA); | 2099 | PHY_INTERFACE_MODE_NA); |
2091 | else | 2100 | else |
2092 | err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, | 2101 | err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, |
2093 | SPEED_UNFORCED, DUPLEX_UNFORCED, | 2102 | SPEED_UNFORCED, DUPLEX_UNFORCED, |
2103 | PAUSE_ON, | ||
2094 | PHY_INTERFACE_MODE_NA); | 2104 | PHY_INTERFACE_MODE_NA); |
2095 | if (err) | 2105 | if (err) |
2096 | return err; | 2106 | return err; |
@@ -2729,6 +2739,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = { | |||
2729 | .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, | 2739 | .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, |
2730 | .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, | 2740 | .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, |
2731 | .port_pause_limit = mv88e6097_port_pause_limit, | 2741 | .port_pause_limit = mv88e6097_port_pause_limit, |
2742 | .port_set_pause = mv88e6185_port_set_pause, | ||
2732 | .stats_snapshot = mv88e6xxx_g1_stats_snapshot, | 2743 | .stats_snapshot = mv88e6xxx_g1_stats_snapshot, |
2733 | .stats_set_histogram = mv88e6095_g1_stats_set_histogram, | 2744 | .stats_set_histogram = mv88e6095_g1_stats_set_histogram, |
2734 | .stats_get_sset_count = mv88e6095_stats_get_sset_count, | 2745 | .stats_get_sset_count = mv88e6095_stats_get_sset_count, |
@@ -3021,6 +3032,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { | |||
3021 | .port_set_egress_floods = mv88e6185_port_set_egress_floods, | 3032 | .port_set_egress_floods = mv88e6185_port_set_egress_floods, |
3022 | .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, | 3033 | .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, |
3023 | .port_set_upstream_port = mv88e6095_port_set_upstream_port, | 3034 | .port_set_upstream_port = mv88e6095_port_set_upstream_port, |
3035 | .port_set_pause = mv88e6185_port_set_pause, | ||
3024 | .stats_snapshot = mv88e6xxx_g1_stats_snapshot, | 3036 | .stats_snapshot = mv88e6xxx_g1_stats_snapshot, |
3025 | .stats_set_histogram = mv88e6095_g1_stats_set_histogram, | 3037 | .stats_set_histogram = mv88e6095_g1_stats_set_histogram, |
3026 | .stats_get_sset_count = mv88e6095_stats_get_sset_count, | 3038 | .stats_get_sset_count = mv88e6095_stats_get_sset_count, |
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 6aa6197ddc10..92ebfd271168 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h | |||
@@ -351,6 +351,13 @@ struct mv88e6xxx_ops { | |||
351 | */ | 351 | */ |
352 | int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup); | 352 | int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup); |
353 | 353 | ||
354 | #define PAUSE_ON 1 | ||
355 | #define PAUSE_OFF 0 | ||
356 | |||
357 | /* Enable/disable sending Pause */ | ||
358 | int (*port_set_pause)(struct mv88e6xxx_chip *chip, int port, | ||
359 | int pause); | ||
360 | |||
354 | #define SPEED_MAX INT_MAX | 361 | #define SPEED_MAX INT_MAX |
355 | #define SPEED_UNFORCED -2 | 362 | #define SPEED_UNFORCED -2 |
356 | 363 | ||
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 429d0ebcd5b1..c0701deaca6a 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c | |||
@@ -36,6 +36,29 @@ int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, | |||
36 | return mv88e6xxx_write(chip, addr, reg, val); | 36 | return mv88e6xxx_write(chip, addr, reg, val); |
37 | } | 37 | } |
38 | 38 | ||
39 | /* Offset 0x00: MAC (or PCS or Physical) Status Register | ||
40 | * | ||
41 | * For most devices, this is read only. However the 6185 has the MyPause | ||
42 | * bit read/write. | ||
43 | */ | ||
44 | int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port, | ||
45 | int pause) | ||
46 | { | ||
47 | u16 reg; | ||
48 | int err; | ||
49 | |||
50 | err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); | ||
51 | if (err) | ||
52 | return err; | ||
53 | |||
54 | if (pause) | ||
55 | reg |= MV88E6XXX_PORT_STS_MY_PAUSE; | ||
56 | else | ||
57 | reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE; | ||
58 | |||
59 | return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg); | ||
60 | } | ||
61 | |||
39 | /* Offset 0x01: MAC (or PCS or Physical) Control Register | 62 | /* Offset 0x01: MAC (or PCS or Physical) Control Register |
40 | * | 63 | * |
41 | * Link, Duplex and Flow Control have one force bit, one value bit. | 64 | * Link, Duplex and Flow Control have one force bit, one value bit. |
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 5e1db1b221ca..44916251567b 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h | |||
@@ -242,6 +242,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, | |||
242 | int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, | 242 | int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, |
243 | u16 val); | 243 | u16 val); |
244 | 244 | ||
245 | int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port, | ||
246 | int pause); | ||
245 | int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, | 247 | int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, |
246 | phy_interface_t mode); | 248 | phy_interface_t mode); |
247 | int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, | 249 | int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, |