linux-tegra.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Revanth Kumar Uppala <ruppala@nvidia.com>
To: <linux@armlinux.org.uk>, <andrew@lunn.ch>, <hkallweit1@gmail.com>,
	<netdev@vger.kernel.org>
Cc: <linux-tegra@vger.kernel.org>,
	Revanth Kumar Uppala <ruppala@nvidia.com>,
	Narayan Reddy <narayanr@nvidia.com>
Subject: [PATCH 4/4] net: phy: aqr113c: Enable Wake-on-LAN (WOL)
Date: Wed, 28 Jun 2023 18:13:26 +0530	[thread overview]
Message-ID: <20230628124326.55732-4-ruppala@nvidia.com> (raw)
In-Reply-To: <20230628124326.55732-1-ruppala@nvidia.com>

Configure the WOL settings in the PHY to allow the PHY to detect magic
packets and generate an interrupt to wake the device from suspend.

The PHY configuration is restored back to XFI once the PHY received the
WOL magic packet.

Note that it is not necessary to poll the PHY status when WOL is enabled
because the interface speed is not being re-configured

Signed-off-by: Narayan Reddy <narayanr@nvidia.com>
Signed-off-by: Revanth Kumar Uppala <ruppala@nvidia.com>
---
 drivers/net/phy/aquantia_main.c | 235 +++++++++++++++++++++++++++++++-
 include/uapi/linux/mdio.h       |   1 +
 2 files changed, 229 insertions(+), 7 deletions(-)

diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
index a27ff4733050..5c69ecd2cf9f 100644
--- a/drivers/net/phy/aquantia_main.c
+++ b/drivers/net/phy/aquantia_main.c
@@ -12,6 +12,7 @@
 #include <linux/delay.h>
 #include <linux/bitfield.h>
 #include <linux/phy.h>
+#include <linux/netdevice.h>
 
 #include "aquantia.h"
 
@@ -48,10 +49,13 @@
 #define MDIO_AN_VEND_PROV_1000BASET_HALF	BIT(14)
 #define MDIO_AN_VEND_PROV_5000BASET_FULL	BIT(11)
 #define MDIO_AN_VEND_PROV_2500BASET_FULL	BIT(10)
+#define MDIO_AN_VEND_PROV_AQRATE_DWN_SHFT_CAP	BIT(12)
 #define MDIO_AN_VEND_PROV_DOWNSHIFT_EN		BIT(4)
 #define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK	GENMASK(3, 0)
 #define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT	4
+#define MDIO_AN_VEND_MASK			0xF0FF
 
+#define MDIO_AN_RSVD_VEND_PROV1			0xc410
 #define MDIO_AN_TX_VEND_STATUS1			0xc800
 #define MDIO_AN_TX_VEND_STATUS1_RATE_MASK	GENMASK(3, 1)
 #define MDIO_AN_TX_VEND_STATUS1_10BASET		0
@@ -61,6 +65,9 @@
 #define MDIO_AN_TX_VEND_STATUS1_2500BASET	4
 #define MDIO_AN_TX_VEND_STATUS1_5000BASET	5
 #define MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX	BIT(0)
+#define MDIO_MMD_AN_WOL_ENABLE			BIT(6)
+
+#define MDIO_AN_RSVD_VEND_STATUS3		0xc812
 
 #define MDIO_AN_TX_VEND_INT_STATUS1		0xcc00
 #define MDIO_AN_TX_VEND_INT_STATUS1_DOWNSHIFT	BIT(1)
@@ -86,6 +93,19 @@
 #define MDIO_AN_RX_VEND_STAT3_AFR		BIT(0)
 
 /* MDIO_MMD_C22EXT */
+#define MDIO_C22EXT_MAGIC_PKT_PATTERN_0_2_15		0xc339
+#define MDIO_C22EXT_MAGIC_PKT_PATTERN_16_2_31		0xc33a
+#define MDIO_C22EXT_MAGIC_PKT_PATTERN_32_2_47		0xc33b
+
+#define MDIO_C22EXT_GBE_PHY_RSI1_CTRL6			0xc355
+#define MDIO_C22EXT_RSI_WAKE_UP_FRAME_DETECTION         BIT(0)
+
+#define MDIO_C22EXT_GBE_PHY_RSI1_CTRL7			0xc356
+#define MDIO_C22EXT_RSI_MAGIC_PKT_FRAME_DETECTION	BIT(0)
+
+#define MDIO_C22EXT_GBE_PHY_RSI1_CTRL8			0xc357
+#define MDIO_C22EXT_RSI_WOL_FCS_MONITOR_MODE		BIT(15)
+
 #define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES		0xd292
 #define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES		0xd294
 #define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER		0xd297
@@ -96,6 +116,11 @@
 #define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS	0xd319
 #define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR	0xd31a
 #define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES		0xd31b
+#define MDIO_C22EXT_GBE_PHY_SGMII_TX_ALARM1		0xec20
+
+#define MDIO_C22EXT_GBE_PHY_SGMII_TX_INT_MASK1		0xf420
+#define MDIO_C22EXT_SGMII0_WAKE_UP_FRAME_MASK		BIT(4)
+#define MDIO_C22EXT_SGMII0_MAGIC_PKT_FRAME_MASK		BIT(5)
 
 /* Vendor specific 1, MDIO_MMD_VEND1 */
 #define VEND1_GLOBAL_FW_ID			0x0020
@@ -109,6 +134,10 @@
 #define VEND1_GLOBAL_CFG_10M			0x0310
 #define VEND1_GLOBAL_CFG_100M			0x031b
 #define VEND1_GLOBAL_CFG_1G			0x031c
+#define VEND1_GLOBAL_SYS_CONFIG_SGMII   (BIT(0) | BIT(1))
+#define VEND1_GLOBAL_SYS_CONFIG_AN      BIT(3)
+#define VEND1_GLOBAL_SYS_CONFIG_XFI     BIT(8)
+
 #define VEND1_GLOBAL_CFG_2_5G			0x031d
 #define VEND1_GLOBAL_CFG_5G			0x031e
 #define VEND1_GLOBAL_CFG_10G			0x031f
@@ -181,6 +210,7 @@ static const struct aqr107_hw_stat aqr107_hw_stats[] = {
 
 struct aqr107_priv {
 	u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
+	int wol_status;
 };
 
 static int aqr107_get_sset_count(struct phy_device *phydev)
@@ -327,9 +357,139 @@ static int aqr_config_intr(struct phy_device *phydev)
 	return 0;
 }
 
+static int aqr113c_wol_enable(struct phy_device *phydev)
+{
+	struct aqr107_priv *priv = phydev->priv;
+	u16 val;
+	int ret;
+
+	/* Disables all advertised speeds except for the WoL
+	 * speed (100BASE-TX FD or 1000BASE-T)
+	 * This is set as per the APP note from Marvel
+	 */
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
+			       MDIO_AN_LD_LOOP_TIMING_ABILITY);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV);
+	if (ret < 0)
+		return ret;
+
+	val = (ret & MDIO_AN_VEND_MASK) |
+	      (MDIO_AN_VEND_PROV_AQRATE_DWN_SHFT_CAP | MDIO_AN_VEND_PROV_1000BASET_FULL);
+	ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV, val);
+	if (ret < 0)
+		return ret;
+
+	/* Enable the magic frame and wake up frame detection for the PHY */
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_C22EXT, MDIO_C22EXT_GBE_PHY_RSI1_CTRL6,
+			       MDIO_C22EXT_RSI_WAKE_UP_FRAME_DETECTION);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_C22EXT, MDIO_C22EXT_GBE_PHY_RSI1_CTRL7,
+			       MDIO_C22EXT_RSI_MAGIC_PKT_FRAME_DETECTION);
+	if (ret < 0)
+		return ret;
+
+	/* Set the WoL enable bit */
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RSVD_VEND_PROV1,
+			       MDIO_MMD_AN_WOL_ENABLE);
+	if (ret < 0)
+		return ret;
+
+	/* Set the WoL INT_N trigger bit */
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_C22EXT, MDIO_C22EXT_GBE_PHY_RSI1_CTRL8,
+			       MDIO_C22EXT_RSI_WOL_FCS_MONITOR_MODE);
+	if (ret < 0)
+		return ret;
+
+	/* Enable Interrupt INT_N Generation at pin level */
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_C22EXT, MDIO_C22EXT_GBE_PHY_SGMII_TX_INT_MASK1,
+			       MDIO_C22EXT_SGMII0_WAKE_UP_FRAME_MASK |
+			       MDIO_C22EXT_SGMII0_MAGIC_PKT_FRAME_MASK);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_STD_MASK,
+			       VEND1_GLOBAL_INT_STD_MASK_ALL);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_VEND_MASK,
+			       VEND1_GLOBAL_INT_VEND_MASK_GBE);
+	if (ret < 0)
+		return ret;
+
+	/* Set the system interface to SGMII */
+	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
+			    VEND1_GLOBAL_CFG_100M, VEND1_GLOBAL_SYS_CONFIG_SGMII |
+			    VEND1_GLOBAL_SYS_CONFIG_AN);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
+			    VEND1_GLOBAL_CFG_1G, VEND1_GLOBAL_SYS_CONFIG_SGMII |
+			    VEND1_GLOBAL_SYS_CONFIG_AN);
+	if (ret < 0)
+		return ret;
+
+	/* restart auto-negotiation */
+	genphy_c45_restart_aneg(phydev);
+	priv->wol_status = 1;
+
+	return 0;
+}
+
+static int aqr113c_wol_disable(struct phy_device *phydev)
+{
+	struct aqr107_priv *priv = phydev->priv;
+	int ret;
+
+	/* Disable the WoL enable bit */
+	ret = phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RSVD_VEND_PROV1,
+				 MDIO_MMD_AN_WOL_ENABLE);
+	if (ret < 0)
+		return ret;
+
+	/* Restore the SERDES/System Interface back to the XFI mode */
+	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
+			    VEND1_GLOBAL_CFG_100M, VEND1_GLOBAL_SYS_CONFIG_XFI);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
+			    VEND1_GLOBAL_CFG_1G, VEND1_GLOBAL_SYS_CONFIG_XFI);
+	if (ret < 0)
+		return ret;
+
+	/* restart auto-negotiation */
+	genphy_c45_restart_aneg(phydev);
+	priv->wol_status = 0;
+
+	return 0;
+}
+
 static irqreturn_t aqr_handle_interrupt(struct phy_device *phydev)
 {
+	struct aqr107_priv *priv = phydev->priv;
 	int irq_status;
+	int ret;
+
+	ret = phy_read_mmd(phydev, MDIO_MMD_C22EXT, MDIO_C22EXT_GBE_PHY_SGMII_TX_ALARM1);
+	if (ret < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if ((ret & MDIO_C22EXT_SGMII0_MAGIC_PKT_FRAME_MASK) ==
+	    MDIO_C22EXT_SGMII0_MAGIC_PKT_FRAME_MASK) {
+		/* Disable the WoL */
+		ret = aqr113c_wol_disable(phydev);
+		if (ret < 0)
+			return IRQ_NONE;
+	}
 
 	irq_status = phy_read_mmd(phydev, MDIO_MMD_AN,
 				  MDIO_AN_TX_VEND_INT_STATUS2);
@@ -425,6 +585,7 @@ static int aqr107_read_rate(struct phy_device *phydev)
 
 static int aqr107_read_status(struct phy_device *phydev)
 {
+	struct aqr107_priv *priv = phydev->priv;
 	int val, ret;
 
 	ret = aqr_read_status(phydev);
@@ -471,14 +632,18 @@ static int aqr107_read_status(struct phy_device *phydev)
 	/* Lane bring-up failures are seen during interface up, as interface
 	 * speed settings are configured while the PHY is still initializing.
 	 * To resolve this, poll until PHY system side interface gets ready
-	 * and the interface speed settings are configured.
+	 * and the interface speed settings are configured.Polling is skipped
+	 * when WoL is enabled because interface speed settings are not
+	 * configured at that time.
 	 */
-	ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS,
-					val, (val & MDIO_PHYXS_VEND_IF_STATUS_TX_READY),
-					20000, 2000000, false);
-	if (ret) {
-		phydev_err(phydev, "PHY system interface is not yet ready\n");
-		return ret;
+	if (!priv->wol_status) {
+		ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS,
+						val, (val & MDIO_PHYXS_VEND_IF_STATUS_TX_READY),
+						20000, 2000000, false);
+		if (ret) {
+			phydev_err(phydev, "PHY system interface is not yet ready\n");
+			return ret;
+		}
 	}
 
 	/* Read possibly downshifted rate from vendor register */
@@ -619,6 +784,31 @@ static int aqr107_config_init(struct phy_device *phydev)
 	if (ret < 0)
 		return ret;
 
+	/* Configure Magic packet frame pattern (MAC address) */
+	ret = phy_write_mmd(phydev, MDIO_MMD_C22EXT, MDIO_C22EXT_MAGIC_PKT_PATTERN_0_2_15,
+			    phydev->attached_dev->dev_addr[0] |
+			    (phydev->attached_dev->dev_addr[1] << 8));
+	if (ret < 0) {
+		phydev_err(phydev, "Error setting magic packet frame of 0/1st byte\n");
+		return ret;
+	}
+
+	ret = phy_write_mmd(phydev, MDIO_MMD_C22EXT, MDIO_C22EXT_MAGIC_PKT_PATTERN_16_2_31,
+			    phydev->attached_dev->dev_addr[2] |
+			    (phydev->attached_dev->dev_addr[3] << 8));
+	if (ret < 0) {
+		phydev_err(phydev, "Error setting magic packet frame of 2/3rd byte\n");
+		return ret;
+	}
+
+	ret = phy_write_mmd(phydev, MDIO_MMD_C22EXT, MDIO_C22EXT_MAGIC_PKT_PATTERN_32_2_47,
+			    phydev->attached_dev->dev_addr[4] |
+			    (phydev->attached_dev->dev_addr[5] << 8));
+	if (ret < 0) {
+		phydev_err(phydev, "Error setting magic packet frame of 4/5th byte\n");
+		return ret;
+	}
+
 	return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
 }
 
@@ -757,6 +947,35 @@ static int aqr107_probe(struct phy_device *phydev)
 	return aqr_hwmon_probe(phydev);
 }
 
+static void aqr113c_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+{
+	int val;
+
+	val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RSVD_VEND_STATUS3);
+	if (val < 0)
+		return;
+
+	wol->supported = WAKE_MAGIC;
+	if (val & 0x1)
+		wol->wolopts = WAKE_MAGIC;
+}
+
+static int aqr113c_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+{
+	struct aqr107_priv *priv = phydev->priv;
+
+	/* Return success if WOL is already set. Don't entertain duplicate setting of WOL */
+	if (!(priv->wol_status ^ wol->wolopts))
+		return 0;
+
+	if (wol->wolopts & WAKE_MAGIC)
+		return aqr113c_wol_enable(phydev);
+	else
+		return aqr113c_wol_disable(phydev);
+
+	return 0;
+}
+
 static struct phy_driver aqr_driver[] = {
 {
 	PHY_ID_MATCH_MODEL(PHY_ID_AQ1202),
@@ -892,6 +1111,8 @@ static struct phy_driver aqr_driver[] = {
 	.get_strings    = aqr107_get_strings,
 	.get_stats      = aqr107_get_stats,
 	.link_change_notify = aqr107_link_change_notify,
+	.get_wol        = &aqr113c_get_wol,
+	.set_wol        = &aqr113c_set_wol,
 },
 };
 
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index b826598d1e94..07ca44891378 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -298,6 +298,7 @@
 #define MDIO_AN_10GBT_CTRL_ADV5G	0x0100	/* Advertise 5GBASE-T */
 #define MDIO_AN_10GBT_CTRL_ADV10G	0x1000	/* Advertise 10GBASE-T */
 
+#define MDIO_AN_LD_LOOP_TIMING_ABILITY	0x0001
 /* AN 10GBASE-T status register. */
 #define MDIO_AN_10GBT_STAT_LP2_5G	0x0020  /* LP is 2.5GBT capable */
 #define MDIO_AN_10GBT_STAT_LP5G		0x0040  /* LP is 5GBT capable */
-- 
2.17.1


  parent reply	other threads:[~2023-06-28 12:45 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-28 12:43 [PATCH 1/4] net: phy: aquantia: Enable Tx/Rx pause frame support in aquantia PHY Revanth Kumar Uppala
2023-06-28 12:43 ` [PATCH 2/4] net: phy: aquantia: Enable MAC Controlled EEE Revanth Kumar Uppala
2023-06-28 13:54   ` Andrew Lunn
2023-07-24 11:29     ` Revanth Kumar Uppala
2023-07-24 11:52       ` Russell King (Oracle)
2023-06-28 12:43 ` [PATCH 3/4] net: phy: aquantia: Poll for TX ready at PHY system side Revanth Kumar Uppala
2023-06-28 13:33   ` Russell King (Oracle)
2023-07-24 11:29     ` Revanth Kumar Uppala
2023-07-24 11:57       ` Russell King (Oracle)
2023-06-28 12:43 ` Revanth Kumar Uppala [this message]
2023-06-28 13:43   ` [PATCH 4/4] net: phy: aqr113c: Enable Wake-on-LAN (WOL) Russell King (Oracle)
2023-07-24 11:29     ` Revanth Kumar Uppala
2023-07-24 12:29       ` Russell King (Oracle)
2023-06-28 14:17   ` Andrew Lunn
2023-07-24 11:30     ` Revanth Kumar Uppala
2023-06-28 18:57   ` kernel test robot
2023-06-28 13:30 ` [PATCH 1/4] net: phy: aquantia: Enable Tx/Rx pause frame support in aquantia PHY Russell King (Oracle)
2023-06-28 13:46   ` Andrew Lunn
2023-07-24 11:29     ` Revanth Kumar Uppala
2023-07-24 11:47       ` Russell King (Oracle)
2023-06-28 13:46 ` Russell King (Oracle)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230628124326.55732-4-ruppala@nvidia.com \
    --to=ruppala@nvidia.com \
    --cc=andrew@lunn.ch \
    --cc=hkallweit1@gmail.com \
    --cc=linux-tegra@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=narayanr@nvidia.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).