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
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240701-b4-dp83869-sfp-v1-5-a71d6d0ad5f8@bootlin.com>
Date: Mon, 01 Jul 2024 10:51:07 +0200
From: Romain Gantois <romain.gantois@...tlin.com>
To: Andrew Lunn <andrew@...n.ch>, Heiner Kallweit <hkallweit1@...il.com>, 
 Russell King <linux@...linux.org.uk>, 
 "David S. Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>, 
 Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>
Cc: Thomas Petazzoni <thomas.petazzoni@...tlin.com>, netdev@...r.kernel.org, 
 linux-kernel@...r.kernel.org, Romain Gantois <romain.gantois@...tlin.com>
Subject: [PATCH net-next 5/6] net: phy: dp83869: Support SGMII SFP modules

The DP83869HM PHY transceiver can be configured in RGMII-SGMII bridge mode
to interface an RGMII MAC with a standard SFP module containing an
integrated PHY. Additional SFP upstream ops are needed to notify the
DP83869 driver of SFP PHY detection so that it can initialize it.

Add relevant SFP callbacks to the DP83869 driver to support SGMII
modules.

Signed-off-by: Romain Gantois <romain.gantois@...tlin.com>
---
 drivers/net/phy/dp83869.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 104 insertions(+)

diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c
index a3ccaad738b28..a07ec1be84baf 100644
--- a/drivers/net/phy/dp83869.c
+++ b/drivers/net/phy/dp83869.c
@@ -153,6 +153,8 @@ struct dp83869_private {
 	bool rxctrl_strap_quirk;
 	int clk_output_sel;
 	int mode;
+	/* PHY in a downstream SFP module */
+	struct phy_device *mod_phy;
 };
 
 static int dp83869_read_status(struct phy_device *phydev)
@@ -845,6 +847,93 @@ static int dp83869_config_init(struct phy_device *phydev)
 	return ret;
 }
 
+static void dp83869_sfp_phy_change(struct phy_device *phydev, bool up)
+{
+	/* phylink uses this to populate its own structs from phy_device fields
+	 * we don't actually need this callback but if we don't implement it
+	 * the phy core will crash
+	 */
+}
+
+static int dp83869_connect_phy(void *upstream, struct phy_device *phy)
+{
+	struct phy_device *phydev = upstream;
+	struct dp83869_private *dp83869;
+
+	dp83869 = phydev->priv;
+
+	if (dp83869->mode != DP83869_RGMII_SGMII_BRIDGE)
+		return 0;
+
+	if (!phy->drv) {
+		dev_warn(&phy->mdio.dev, "No driver bound to SFP module phy!\n");
+		return 0;
+	}
+
+	phy_support_asym_pause(phy);
+	linkmode_set_bit(PHY_INTERFACE_MODE_SGMII, phy->host_interfaces);
+	phy->interface = PHY_INTERFACE_MODE_SGMII;
+	phy->port = PORT_TP;
+
+	phy->speed = SPEED_UNKNOWN;
+	phy->duplex = DUPLEX_UNKNOWN;
+	phy->pause = MLO_PAUSE_NONE;
+	phy->interrupts = PHY_INTERRUPT_DISABLED;
+	phy->irq = PHY_POLL;
+	phy->phy_link_change = &dp83869_sfp_phy_change;
+	phy->state = PHY_READY;
+
+	dp83869->mod_phy = phy;
+
+	return 0;
+}
+
+static void dp83869_disconnect_phy(void *upstream)
+{
+	struct phy_device *phydev = upstream;
+	struct dp83869_private *dp83869;
+
+	dp83869 = phydev->priv;
+	dp83869->mod_phy = NULL;
+}
+
+static int dp83869_module_start(void *upstream)
+{
+	struct phy_device *phydev = upstream;
+	struct dp83869_private *dp83869;
+	struct phy_device *mod_phy;
+	int ret;
+
+	dp83869 = phydev->priv;
+	mod_phy = dp83869->mod_phy;
+	if (!mod_phy)
+		return 0;
+
+	ret = phy_init_hw(mod_phy);
+	if (ret) {
+		dev_err(&mod_phy->mdio.dev, "Failed to initialize PHY hardware: error %d", ret);
+		return ret;
+	}
+
+	phy_start(mod_phy);
+
+	return 0;
+}
+
+static void dp83869_module_stop(void *upstream)
+{
+	struct phy_device *phydev = upstream;
+	struct dp83869_private *dp83869;
+	struct phy_device *mod_phy;
+
+	dp83869 = phydev->priv;
+	mod_phy = dp83869->mod_phy;
+	if (!mod_phy)
+		return;
+
+	phy_stop(mod_phy);
+}
+
 static int dp83869_module_insert(void *upstream, const struct sfp_eeprom_id *id)
 {
 	__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
@@ -858,6 +947,13 @@ static int dp83869_module_insert(void *upstream, const struct sfp_eeprom_id *id)
 	phylink_set(phy_support, 1000baseX_Full);
 	phylink_set(phy_support, 100baseFX_Full);
 	phylink_set(phy_support, FIBRE);
+	phylink_set(phy_support, 10baseT_Full);
+	phylink_set(phy_support, 100baseT_Full);
+	phylink_set(phy_support, 1000baseT_Full);
+	phylink_set(phy_support, Autoneg);
+	phylink_set(phy_support, Pause);
+	phylink_set(phy_support, Asym_Pause);
+	phylink_set(phy_support, TP);
 
 	linkmode_zero(sfp_support);
 	sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
@@ -877,6 +973,10 @@ static int dp83869_module_insert(void *upstream, const struct sfp_eeprom_id *id)
 	dp83869 = phydev->priv;
 
 	switch (interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+		dp83869->mode = DP83869_RGMII_SGMII_BRIDGE;
+		phydev->port = PORT_TP;
+		break;
 	case PHY_INTERFACE_MODE_100BASEX:
 		dp83869->mode = DP83869_RGMII_100_BASE;
 		phydev->port = PORT_FIBRE;
@@ -899,6 +999,10 @@ static const struct sfp_upstream_ops dp83869_sfp_ops = {
 	.attach = phy_sfp_attach,
 	.detach = phy_sfp_detach,
 	.module_insert = dp83869_module_insert,
+	.module_start = dp83869_module_start,
+	.module_stop = dp83869_module_stop,
+	.connect_phy = dp83869_connect_phy,
+	.disconnect_phy = dp83869_disconnect_phy,
 };
 
 static int dp83869_probe(struct phy_device *phydev)

-- 
2.45.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ