net: dsa: mv88e6xxx: support in-band signalling on SGMII ports with external PHYs

If an external PHY is connected via SGMII and uses in-band signalling
then the auto-negotiated values aren't propagated to the port,
resulting in a broken link. See discussion in [0]. This patch adds
this propagation. We need to call mv88e6xxx_port_setup_mac(),
therefore export it from chip.c.

Successfully tested on a ZII DTU with 88E6390 switch and an
Aquantia AQCS109 PHY connected via SGMII to port 9.

[0] https://marc.info/?t=155130287200001&r=1&w=2

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Heiner Kallweit
2019-03-01 20:41:00 +01:00
committed by David S. Miller
orang tua 80f61f19e5
melakukan 72d8b4fdbf
4 mengubah file dengan 52 tambahan dan 14 penghapusan

Melihat File

@@ -510,21 +510,48 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
int port, int lane)
{
struct dsa_switch *ds = chip->ds;
int duplex = DUPLEX_UNKNOWN;
int speed = SPEED_UNKNOWN;
int link, err;
u16 status;
bool up;
mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
MV88E6390_SGMII_STATUS, &status);
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
MV88E6390_SGMII_PHY_STATUS, &status);
if (err) {
dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err);
return;
}
/* Status must be read twice in order to give the current link
* status. Otherwise the change in link status since the last
* read of the register is returned.
*/
mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
MV88E6390_SGMII_STATUS, &status);
up = status & MV88E6390_SGMII_STATUS_LINK;
link = status & MV88E6390_SGMII_PHY_STATUS_LINK ?
LINK_FORCED_UP : LINK_FORCED_DOWN;
dsa_port_phylink_mac_change(ds, port, up);
if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
duplex = status & MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
DUPLEX_FULL : DUPLEX_HALF;
switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
speed = SPEED_1000;
break;
case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
speed = SPEED_100;
break;
case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
speed = SPEED_10;
break;
default:
dev_err(chip->dev, "invalid PHY speed\n");
return;
}
}
err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex,
PAUSE_OFF, PHY_INTERFACE_MODE_NA);
if (err)
dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n",
err);
else
dsa_port_phylink_mac_change(ds, port, link == LINK_FORCED_UP);
}
static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,