Skip to content

Commit

Permalink
Merge branch 'More-complete-PHYLINK-support-for-mv88e6xxx'
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David S. Miller committed Aug 9, 2018
2 parents 78b3906 + 734447d commit ff50eda
Show file tree
Hide file tree
Showing 8 changed files with 767 additions and 109 deletions.
226 changes: 219 additions & 7 deletions drivers/net/dsa/mv88e6xxx/chip.c

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions drivers/net/dsa/mv88e6xxx/chip.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand Down
109 changes: 105 additions & 4 deletions drivers/net/dsa/mv88e6xxx/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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, &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
*
* Link, Duplex and Flow Control have one force bit, one value bit.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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, &reg);
if (err)
Expand All @@ -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, &reg);
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;
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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
Expand Down
23 changes: 21 additions & 2 deletions drivers/net/dsa/mv88e6xxx/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit ff50eda

Please sign in to comment.