All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next] net: dsa: mv88e6xxx: support in-band signalling on SGMII ports with external PHYs
@ 2019-03-01 19:41 Heiner Kallweit
  2019-03-04 18:52 ` David Miller
  0 siblings, 1 reply; 2+ messages in thread
From: Heiner Kallweit @ 2019-03-01 19:41 UTC (permalink / raw)
  To: Vivien Didelot, Andrew Lunn, Florian Fainelli, David Miller
  Cc: netdev, Russell King - ARM Linux

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>
---
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


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH net-next] net: dsa: mv88e6xxx: support in-band signalling on SGMII ports with external PHYs
  2019-03-01 19:41 [PATCH net-next] net: dsa: mv88e6xxx: support in-band signalling on SGMII ports with external PHYs Heiner Kallweit
@ 2019-03-04 18:52 ` David Miller
  0 siblings, 0 replies; 2+ messages in thread
From: David Miller @ 2019-03-04 18:52 UTC (permalink / raw)
  To: hkallweit1; +Cc: vivien.didelot, andrew, f.fainelli, netdev, linux

From: Heiner Kallweit <hkallweit1@gmail.com>
Date: Fri, 1 Mar 2019 20:41:00 +0100

> 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>
> ---
> I consider this rather a missing feature than a bug. Therefore net-next.

Applied to net-next, thanks Heiner.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-03-04 18:53 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-01 19:41 [PATCH net-next] net: dsa: mv88e6xxx: support in-band signalling on SGMII ports with external PHYs Heiner Kallweit
2019-03-04 18:52 ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.