lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-ID: <3e483c0c-0822-d185-1df5-3bb046ebd400@gmail.com> Date: Fri, 1 Mar 2019 20:41:00 +0100 From: Heiner Kallweit <hkallweit1@...il.com> To: Vivien Didelot <vivien.didelot@...il.com>, Andrew Lunn <andrew@...n.ch>, Florian Fainelli <f.fainelli@...il.com>, David Miller <davem@...emloft.net> Cc: "netdev@...r.kernel.org" <netdev@...r.kernel.org>, Russell King - ARM Linux <linux@...linux.org.uk> Subject: [PATCH net-next] 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@...il.com> --- I consider this rather a missing feature than a bug. Therefore net-next. --- drivers/net/dsa/mv88e6xxx/chip.c | 6 ++-- drivers/net/dsa/mv88e6xxx/chip.h | 3 ++ drivers/net/dsa/mv88e6xxx/serdes.c | 49 +++++++++++++++++++++++------- drivers/net/dsa/mv88e6xxx/serdes.h | 8 +++++ 4 files changed, 52 insertions(+), 14 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 47128cae2..d9f311791 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -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; diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 546651d8c..adcf60779 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -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 */ diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 1bfc5ff8d..6a5de1b72 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -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; + + 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; + } + } - dsa_port_phylink_mac_change(ds, port, up); + 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, diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index 573dce8b1..c2e7eedfa 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -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); -- 2.21.0
Powered by blists - more mailing lists