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:
Родитель
80f61f19e5
Коммит
72d8b4fdbf
|
@ -549,9 +549,9 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
|
|||
return mv88e6xxx_write(chip, addr, reg, val);
|
||||
}
|
||||
|
||||
static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
|
||||
int link, int speed, int duplex, int pause,
|
||||
phy_interface_t mode)
|
||||
int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
|
||||
int speed, int duplex, int pause,
|
||||
phy_interface_t mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
|
|
@ -579,6 +579,9 @@ int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
|
|||
int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg,
|
||||
u16 update);
|
||||
int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask);
|
||||
int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
|
||||
int speed, int duplex, int pause,
|
||||
phy_interface_t mode);
|
||||
struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip);
|
||||
|
||||
#endif /* _MV88E6XXX_CHIP_H */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -69,6 +69,14 @@
|
|||
#define MV88E6390_SGMII_INT_SYMBOL_ERROR BIT(8)
|
||||
#define MV88E6390_SGMII_INT_FALSE_CARRIER BIT(7)
|
||||
#define MV88E6390_SGMII_INT_STATUS 0xa002
|
||||
#define MV88E6390_SGMII_PHY_STATUS 0xa003
|
||||
#define MV88E6390_SGMII_PHY_STATUS_SPEED_MASK GENMASK(15, 14)
|
||||
#define MV88E6390_SGMII_PHY_STATUS_SPEED_1000 0x8000
|
||||
#define MV88E6390_SGMII_PHY_STATUS_SPEED_100 0x4000
|
||||
#define MV88E6390_SGMII_PHY_STATUS_SPEED_10 0x0000
|
||||
#define MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL BIT(13)
|
||||
#define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11)
|
||||
#define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10)
|
||||
|
||||
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
|
||||
|
|
Загрузка…
Ссылка в новой задаче