if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) { /* The Spped and Duplex Resolved register is 1 if AN is enabled * and complete, or if AN is disabled. So with disabled AN we * still get here on link up.
*/
state->duplex = status &
MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
DUPLEX_FULL : DUPLEX_HALF;
if (status & MV88E6390_SGMII_PHY_STATUS_TX_PAUSE)
state->pause |= MLO_PAUSE_TX; if (status & MV88E6390_SGMII_PHY_STATUS_RX_PAUSE)
state->pause |= MLO_PAUSE_RX;
switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) { case MV88E6390_SGMII_PHY_STATUS_SPEED_1000: if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
state->speed = SPEED_2500; else
state->speed = SPEED_1000; break; case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
state->speed = SPEED_100; break; case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
state->speed = SPEED_10; break; default:
dev_err(dev, "invalid PHY speed\n"); return -EINVAL;
}
} elseif (state->link &&
state->interface != PHY_INTERFACE_MODE_SGMII) { /* If Speed and Duplex Resolved register is 0 and link is up, it * means that AN was enabled, but link partner had it disabled * and the PHY invoked the Auto-Negotiation Bypass feature and * linked anyway.
*/
state->duplex = DUPLEX_FULL; if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
state->speed = SPEED_2500; else
state->speed = SPEED_1000;
} else {
state->link = false;
}
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
{ int err;
err = mv88e6352_g2_scratch_port_has_serdes(chip, port); if (err <= 0) return err;
return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
}
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port,
uint8_t **data)
{ struct mv88e6352_serdes_hw_stat *stat; int err, i;
err = mv88e6352_g2_scratch_port_has_serdes(chip, port); if (err <= 0) return err;
for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
stat = &mv88e6352_serdes_hw_stats[i];
ethtool_puts(data, stat->string);
} return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
}
static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip, struct mv88e6352_serdes_hw_stat *stat)
{
u64 val = 0;
u16 reg; int err;
err = mv88e6352_serdes_read(chip, stat->reg, ®); if (err) {
dev_err(chip->dev, "failed to read statistic\n"); return 0;
}
val = reg;
if (stat->sizeof_stat == 32) {
err = mv88e6352_serdes_read(chip, stat->reg + 1, ®); if (err) {
dev_err(chip->dev, "failed to read statistic\n"); return 0;
}
val = val << 16 | reg;
}
return val;
}
size_t mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
{ struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port]; struct mv88e6352_serdes_hw_stat *stat; int i, err;
u64 value;
err = mv88e6352_g2_scratch_port_has_serdes(chip, port); if (err <= 0) return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
stat = &mv88e6352_serdes_hw_stats[i];
value = mv88e6352_serdes_get_stat(chip, stat);
mv88e6xxx_port->serdes_stats[i] += value;
data[i] = mv88e6xxx_port->serdes_stats[i];
}
void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
{
u16 *p = _p;
u16 reg; int err; int i;
err = mv88e6352_g2_scratch_port_has_serdes(chip, port); if (err <= 0) return;
for (i = 0 ; i < 32; i++) {
err = mv88e6352_serdes_read(chip, i, ®); if (!err)
p[i] = reg;
}
}
int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode; int lane = -ENODEV;
switch (port) { case 5: if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
lane = MV88E6341_PORT5_LANE; break;
}
return lane;
}
int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode; int lane = -ENODEV;
switch (port) { case 9: if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
lane = MV88E6390_PORT9_LANE0; break; case 10: if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
lane = MV88E6390_PORT10_LANE0; break;
}
return lane;
}
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode_port = chip->ports[port].cmode;
u8 cmode_port10 = chip->ports[10].cmode;
u8 cmode_port9 = chip->ports[9].cmode; int lane = -ENODEV;
switch (port) { case 2: if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
lane = MV88E6390_PORT9_LANE1; break; case 3: if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
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_1000BASEX)
lane = MV88E6390_PORT9_LANE2; break; case 4: if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
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_1000BASEX)
lane = MV88E6390_PORT9_LANE3; break; case 5: if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
lane = MV88E6390_PORT10_LANE1; break; case 6: if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
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_1000BASEX)
lane = MV88E6390_PORT10_LANE2; break; case 7: if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
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_1000BASEX)
lane = MV88E6390_PORT10_LANE3; break; case 9: if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
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)
lane = MV88E6390_PORT9_LANE0; break; case 10: if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
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)
lane = MV88E6390_PORT10_LANE0; break;
}
return lane;
}
/* Only Ports 0, 9 and 10 have SERDES lanes. Return the SERDES lane address * a port is using else Returns -ENODEV.
*/ int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode; int lane = -ENODEV;
if (port != 0 && port != 9 && port != 10) return -EOPNOTSUPP;
int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
{ if (mv88e6xxx_serdes_get_lane(chip, port) < 0) return 0;
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
}
int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, int port,
uint8_t **data)
{ struct mv88e6390_serdes_hw_stat *stat; int i;
if (mv88e6xxx_serdes_get_lane(chip, port) < 0) return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
stat = &mv88e6390_serdes_hw_stats[i];
ethtool_puts(data, stat->string);
} return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
}
static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane, struct mv88e6390_serdes_hw_stat *stat)
{
u16 reg[3]; int err, i;
for (i = 0; i < 3; i++) {
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
stat->reg + i, ®[i]); if (err) {
dev_err(chip->dev, "failed to read statistic\n"); return 0;
}
}
size_t mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
{ struct mv88e6390_serdes_hw_stat *stat; int lane; int i;
lane = mv88e6xxx_serdes_get_lane(chip, port); if (lane < 0) return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
stat = &mv88e6390_serdes_hw_stats[i];
data[i] = mv88e6390_serdes_get_stat(chip, lane, stat);
}
void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
{
u16 *p = _p; int lane;
u16 reg; int err; int i;
lane = mv88e6xxx_serdes_get_lane(chip, port); if (lane < 0) return;
for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
mv88e6390_serdes_regs[i], ®); if (!err)
p[i] = reg;
}
}
staticconstint mv88e6352_serdes_p2p_to_reg[] = { /* Index of value in microvolts corresponds to the register value */
14000, 112000, 210000, 308000, 406000, 504000, 602000, 700000,
};
int mv88e6352_serdes_set_tx_amplitude(struct mv88e6xxx_chip *chip, int port, int val)
{ bool found = false;
u16 ctrl, reg; int err; int i;
err = mv88e6352_g2_scratch_port_has_serdes(chip, port); if (err <= 0) return err;
for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_p2p_to_reg); ++i) { if (mv88e6352_serdes_p2p_to_reg[i] == val) {
reg = i;
found = true; break;
}
}
if (!found) return -EINVAL;
err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_SPEC_CTRL2, &ctrl); if (err) return err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.