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] [day] [month] [year] [list]
Message-ID: <20250619144423.2661528-2-shaojijie@huawei.com>
Date: Thu, 19 Jun 2025 22:44:21 +0800
From: Jijie Shao <shaojijie@...wei.com>
To: <davem@...emloft.net>, <edumazet@...gle.com>, <kuba@...nel.org>,
	<pabeni@...hat.com>, <andrew+netdev@...n.ch>, <horms@...nel.org>
CC: <shenjian15@...wei.com>, <wangpeiyang1@...wei.com>,
	<liuyonglong@...wei.com>, <chenhao418@...wei.com>,
	<jonathan.cameron@...wei.com>, <shameerali.kolothum.thodi@...wei.com>,
	<salil.mehta@...wei.com>, <netdev@...r.kernel.org>,
	<linux-kernel@...r.kernel.org>, <shaojijie@...wei.com>
Subject: [PATCH net-next 1/3] net: hibmcge: support scenario without PHY.

Currently, the driver uses phylib to operate PHY by default.

On some boards, the PHY device is separated from the MAC device.
As a result, the hibmcge driver cannot operate the PHY device.

In this patch, the driver determines whether a PHY is available
based on register configuration. If no PHY is available,
the driver intercepts phylib operations and operates only MAC device.

Signed-off-by: Jijie Shao <shaojijie@...wei.com>
---
 .../ethernet/hisilicon/hibmcge/hbg_diagnose.c |   6 +-
 .../net/ethernet/hisilicon/hibmcge/hbg_err.c  |   3 +
 .../ethernet/hisilicon/hibmcge/hbg_ethtool.c  | 100 +++++++++++++++++-
 .../net/ethernet/hisilicon/hibmcge/hbg_main.c |  41 ++++++-
 .../net/ethernet/hisilicon/hibmcge/hbg_mdio.c |  76 ++++++++++---
 .../net/ethernet/hisilicon/hibmcge/hbg_mdio.h |   3 +
 .../net/ethernet/hisilicon/hibmcge/hbg_reg.h  |   1 +
 7 files changed, 209 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_diagnose.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_diagnose.c
index f23fb5920c3c..c38ab7c0a69a 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_diagnose.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_diagnose.c
@@ -274,7 +274,11 @@ static int hbg_push_link_status(struct hbg_priv *priv)
 	u32 link_status[2];
 
 	/* phy link status */
-	link_status[0] = priv->mac.phydev->link;
+	if (priv->mac.phydev)
+		link_status[0] = priv->mac.phydev->link;
+	else
+		link_status[0] = 0;
+
 	/* mac link status */
 	link_status[1] = hbg_reg_read_field(priv, HBG_REG_AN_NEG_STATE_ADDR,
 					    HBG_REG_AN_NEG_STATE_NP_LINK_OK_B);
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_err.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_err.c
index ff3295b60a69..2d08f1891cba 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_err.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_err.c
@@ -35,6 +35,9 @@ static void hbg_restore_user_def_settings(struct hbg_priv *priv)
 	hbg_hw_set_pause_enable(priv, pause_param->tx_pause,
 				pause_param->rx_pause);
 	hbg_hw_set_rx_pause_mac_addr(priv, rx_pause_addr);
+
+	if (!priv->mac.phydev)
+		hbg_hw_adjust_link(priv, priv->mac.speed, priv->mac.duplex);
 }
 
 int hbg_rebuild(struct hbg_priv *priv)
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c
index 55520053270a..27121bb53315 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c
@@ -8,6 +8,7 @@
 #include "hbg_err.h"
 #include "hbg_ethtool.h"
 #include "hbg_hw.h"
+#include "hbg_mdio.h"
 
 struct hbg_ethtool_stats {
 	char name[ETH_GSTRING_LEN];
@@ -290,7 +291,10 @@ static int hbg_ethtool_set_pauseparam(struct net_device *net_dev,
 	struct hbg_priv *priv = netdev_priv(net_dev);
 
 	priv->mac.pause_autoneg = param->autoneg;
-	phy_set_asym_pause(priv->mac.phydev, param->rx_pause, param->tx_pause);
+
+	if (priv->mac.phydev)
+		phy_set_asym_pause(priv->mac.phydev,
+				   param->rx_pause, param->tx_pause);
 
 	if (!param->autoneg)
 		hbg_hw_set_pause_enable(priv, param->tx_pause, param->rx_pause);
@@ -474,16 +478,102 @@ hbg_ethtool_get_rmon_stats(struct net_device *netdev,
 	*ranges = hbg_rmon_ranges;
 }
 
+static int
+hbg_ethtool_get_link_ksettings_no_phy(struct hbg_priv *priv,
+				      struct ethtool_link_ksettings *cmd)
+{
+	u32 supported;
+
+	supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+		     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+		     SUPPORTED_1000baseT_Full | SUPPORTED_TP);
+
+	cmd->base.speed = hbg_convert_mac_speed_to_phy(priv->mac.speed);
+	cmd->base.duplex = priv->mac.duplex;
+	cmd->base.autoneg = priv->mac.autoneg;
+	cmd->base.phy_address = priv->mac.phy_addr;
+	cmd->base.port = PORT_TP;
+	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+						supported);
+	return 0;
+}
+
+static int hbg_ethtool_get_link_ksettings(struct net_device *netdev,
+					  struct ethtool_link_ksettings *cmd)
+{
+	struct hbg_priv *priv = netdev_priv(netdev);
+
+	if (priv->mac.phydev)
+		return phy_ethtool_get_link_ksettings(netdev, cmd);
+	else
+		return hbg_ethtool_get_link_ksettings_no_phy(priv, cmd);
+}
+
+static int
+hbg_ethtool_set_link_ksettings_no_phy(struct hbg_priv *priv,
+				      const struct ethtool_link_ksettings *cmd)
+{
+	u32 speed;
+
+	if (cmd->base.autoneg) {
+		netdev_err(priv->netdev, "cannot set autoneg without phy\n");
+		return -EINVAL;
+	}
+
+	speed = hbg_convert_phy_speed_to_mac(cmd->base.speed);
+	if (speed == HBG_PORT_MODE_SGMII_UNKNOWN ||
+	    (speed == HBG_PORT_MODE_SGMII_1000M &&
+	     cmd->base.duplex != DUPLEX_FULL))
+		return -EINVAL;
+
+	priv->mac.speed = speed;
+	priv->mac.duplex = cmd->base.duplex;
+	hbg_hw_adjust_link(priv, priv->mac.speed, priv->mac.duplex);
+	return 0;
+}
+
+static int
+hbg_ethtool_set_link_ksettings(struct net_device *netdev,
+			       const struct ethtool_link_ksettings *cmd)
+{
+	struct hbg_priv *priv = netdev_priv(netdev);
+
+	if (priv->mac.phydev)
+		return phy_ethtool_set_link_ksettings(netdev, cmd);
+	else
+		return hbg_ethtool_set_link_ksettings_no_phy(priv, cmd);
+}
+
+static u32 hbg_ethtool_get_link(struct net_device *netdev)
+{
+	struct hbg_priv *priv = netdev_priv(netdev);
+
+	if (priv->mac.phydev)
+		return ethtool_op_get_link(netdev);
+
+	return priv->mac.link_status;
+}
+
+static int hbg_ethtool_nway_reset(struct net_device *netdev)
+{
+	struct hbg_priv *priv = netdev_priv(netdev);
+
+	if (!priv->mac.phydev)
+		return -EOPNOTSUPP;
+
+	return phy_ethtool_nway_reset(netdev);
+}
+
 static const struct ethtool_ops hbg_ethtool_ops = {
-	.get_link		= ethtool_op_get_link,
-	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
-	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
+	.get_link		= hbg_ethtool_get_link,
+	.get_link_ksettings	= hbg_ethtool_get_link_ksettings,
+	.set_link_ksettings	= hbg_ethtool_set_link_ksettings,
 	.get_regs_len		= hbg_ethtool_get_regs_len,
 	.get_regs		= hbg_ethtool_get_regs,
 	.get_pauseparam         = hbg_ethtool_get_pauseparam,
 	.set_pauseparam         = hbg_ethtool_set_pauseparam,
 	.reset			= hbg_ethtool_reset,
-	.nway_reset		= phy_ethtool_nway_reset,
+	.nway_reset		= hbg_ethtool_nway_reset,
 	.get_sset_count		= hbg_ethtool_get_sset_count,
 	.get_strings		= hbg_ethtool_get_strings,
 	.get_ethtool_stats	= hbg_ethtool_get_stats,
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
index 2e64dc1ab355..93b7cdfbf54e 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
@@ -19,6 +19,8 @@
 #define HBG_SUPPORT_FEATURES (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
 			     NETIF_F_RXCSUM)
 
+static void hbg_update_link_status(struct hbg_priv *priv);
+
 static void hbg_all_irq_enable(struct hbg_priv *priv, bool enabled)
 {
 	const struct hbg_irq_info *info;
@@ -42,7 +44,11 @@ static int hbg_net_open(struct net_device *netdev)
 	hbg_all_irq_enable(priv, true);
 	hbg_hw_mac_enable(priv, HBG_STATUS_ENABLE);
 	netif_start_queue(netdev);
-	hbg_phy_start(priv);
+
+	if (priv->mac.phydev)
+		hbg_phy_start(priv);
+	else
+		hbg_hw_adjust_link(priv, priv->mac.speed, priv->mac.duplex);
 
 	return 0;
 }
@@ -67,11 +73,15 @@ static int hbg_net_stop(struct net_device *netdev)
 {
 	struct hbg_priv *priv = netdev_priv(netdev);
 
-	hbg_phy_stop(priv);
+	if (priv->mac.phydev)
+		hbg_phy_stop(priv);
+
 	netif_stop_queue(netdev);
 	hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE);
 	hbg_all_irq_enable(priv, false);
 	hbg_txrx_uninit(priv);
+
+	hbg_update_link_status(priv);
 	return hbg_hw_txrx_clear(priv);
 }
 
@@ -281,6 +291,32 @@ static const struct net_device_ops hbg_netdev_ops = {
 	.ndo_eth_ioctl		= phy_do_ioctl_running,
 };
 
+static void hbg_update_link_status(struct hbg_priv *priv)
+{
+	u8 link = 0;
+
+	/* if have phy, use phylib to update link status */
+	if (priv->mac.phydev)
+		return;
+
+	if (netif_running(priv->netdev))
+		link = hbg_reg_read_field(priv, HBG_REG_AN_NEG_STATE_ADDR,
+					  HBG_REG_AN_NEG_STATE_NP_LINK_OK_B);
+	if (link == priv->mac.link_status)
+		return;
+
+	if (link) {
+		netif_tx_wake_all_queues(priv->netdev);
+		netif_carrier_on(priv->netdev);
+	} else {
+		netif_carrier_off(priv->netdev);
+		netif_tx_stop_all_queues(priv->netdev);
+	}
+
+	priv->mac.link_status = link;
+	hbg_print_link_status(priv);
+}
+
 static void hbg_service_task(struct work_struct *work)
 {
 	struct hbg_priv *priv = container_of(work, struct hbg_priv,
@@ -292,6 +328,7 @@ static void hbg_service_task(struct work_struct *work)
 	if (test_and_clear_bit(HBG_NIC_STATE_NP_LINK_FAIL, &priv->state))
 		hbg_fix_np_link_fail(priv);
 
+	hbg_update_link_status(priv);
 	hbg_diagnose_message_push(priv);
 
 	/* The type of statistics register is u32,
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c
index 42b0083c9193..5f27b530bd81 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c
@@ -20,6 +20,8 @@
 
 #define HBG_NP_LINK_FAIL_RETRY_TIMES	5
 
+#define HBG_UNUSE_PHY	0xFF
+
 static void hbg_mdio_set_command(struct hbg_mac *mac, u32 cmd)
 {
 	hbg_reg_write(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_ADDR, cmd);
@@ -134,6 +136,11 @@ void hbg_fix_np_link_fail(struct hbg_priv *priv)
 {
 	struct device *dev = &priv->pdev->dev;
 
+	if (!priv->mac.phydev) {
+		dev_err(dev, "failed to link between MAC and PHY\n");
+		return;
+	}
+
 	rtnl_lock();
 
 	if (priv->stats.np_link_fail_cnt >= HBG_NP_LINK_FAIL_RETRY_TIMES) {
@@ -158,6 +165,53 @@ void hbg_fix_np_link_fail(struct hbg_priv *priv)
 	rtnl_unlock();
 }
 
+int hbg_convert_mac_speed_to_phy(u32 mac_speed)
+{
+	switch (mac_speed) {
+	case HBG_PORT_MODE_SGMII_10M:
+		return SPEED_10;
+	case HBG_PORT_MODE_SGMII_100M:
+		return SPEED_100;
+	case HBG_PORT_MODE_SGMII_1000M:
+		return SPEED_1000;
+	default:
+		return SPEED_UNKNOWN;
+	}
+}
+
+u32 hbg_convert_phy_speed_to_mac(int phy_speed)
+{
+	switch (phy_speed) {
+	case SPEED_10:
+		return HBG_PORT_MODE_SGMII_10M;
+	case SPEED_100:
+		return HBG_PORT_MODE_SGMII_100M;
+	case SPEED_1000:
+		return HBG_PORT_MODE_SGMII_1000M;
+	default:
+		return HBG_PORT_MODE_SGMII_UNKNOWN;
+	}
+}
+
+void hbg_print_link_status(struct hbg_priv *priv)
+{
+	u32 speed;
+
+	if (priv->mac.phydev) {
+		phy_print_status(priv->mac.phydev);
+		return;
+	}
+
+	if (priv->mac.link_status) {
+		speed = hbg_convert_mac_speed_to_phy(priv->mac.speed);
+		netdev_info(priv->netdev, "Link is Up - %s/%s\n",
+			    phy_speed_to_str(speed),
+			    phy_duplex_to_str(priv->mac.duplex));
+	} else {
+		netdev_info(priv->netdev, "Link is Down\n");
+	}
+}
+
 static void hbg_phy_adjust_link(struct net_device *netdev)
 {
 	struct hbg_priv *priv = netdev_priv(netdev);
@@ -166,19 +220,9 @@ static void hbg_phy_adjust_link(struct net_device *netdev)
 
 	if (phydev->link != priv->mac.link_status) {
 		if (phydev->link) {
-			switch (phydev->speed) {
-			case SPEED_10:
-				speed = HBG_PORT_MODE_SGMII_10M;
-				break;
-			case SPEED_100:
-				speed = HBG_PORT_MODE_SGMII_100M;
-				break;
-			case SPEED_1000:
-				speed = HBG_PORT_MODE_SGMII_1000M;
-				break;
-			default:
+			speed = hbg_convert_phy_speed_to_mac(phydev->speed);
+			if (speed == HBG_PORT_MODE_SGMII_UNKNOWN)
 				return;
-			}
 
 			priv->mac.speed = speed;
 			priv->mac.duplex = phydev->duplex;
@@ -188,7 +232,7 @@ static void hbg_phy_adjust_link(struct net_device *netdev)
 		}
 
 		priv->mac.link_status = phydev->link;
-		phy_print_status(phydev);
+		hbg_print_link_status(priv);
 	}
 }
 
@@ -238,6 +282,12 @@ int hbg_mdio_init(struct hbg_priv *priv)
 	int ret;
 
 	mac->phy_addr = priv->dev_specs.phy_addr;
+	if (mac->phy_addr == HBG_UNUSE_PHY) {
+		mac->duplex = 1;
+		mac->speed = HBG_PORT_MODE_SGMII_1000M;
+		return 0;
+	}
+
 	mdio_bus = devm_mdiobus_alloc(dev);
 	if (!mdio_bus)
 		return dev_err_probe(dev, -ENOMEM,
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h
index f3771c1bbd34..64c1f79b434c 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h
@@ -10,5 +10,8 @@ int hbg_mdio_init(struct hbg_priv *priv);
 void hbg_phy_start(struct hbg_priv *priv);
 void hbg_phy_stop(struct hbg_priv *priv);
 void hbg_fix_np_link_fail(struct hbg_priv *priv);
+int hbg_convert_mac_speed_to_phy(u32 mac_speed);
+u32 hbg_convert_phy_speed_to_mac(int phy_speed);
+void hbg_print_link_status(struct hbg_priv *priv);
 
 #endif
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
index a6e7f5e62b48..eb50b202ca3a 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
@@ -218,6 +218,7 @@ enum hbg_port_mode {
 	HBG_PORT_MODE_SGMII_10M = 0x6,
 	HBG_PORT_MODE_SGMII_100M = 0x7,
 	HBG_PORT_MODE_SGMII_1000M = 0x8,
+	HBG_PORT_MODE_SGMII_UNKNOWN = 0x9,
 };
 
 struct hbg_tx_desc {
-- 
2.33.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ