diff mbox series

net: phy: rtl8211f add ethtool set wol function

Message ID 20240602084657.5222-1-yangfeng59949@163.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series net: phy: rtl8211f add ethtool set wol function | expand

Checks

Context Check Description
netdev/series_format warning Single patches do not need cover letters; Target tree name not specified in the subject
netdev/tree_selection success Guessed tree name to be net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 901 this patch: 901
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 3 maintainers not CCed: pabeni@redhat.com kuba@kernel.org edumazet@google.com
netdev/build_clang success Errors and warnings before: 905 this patch: 905
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 905 this patch: 905
netdev/checkpatch warning CHECK: Alignment should match open parenthesis
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-06-03--15-00 (tests: 1041)

Commit Message

yangfeng June 2, 2024, 8:46 a.m. UTC
From: Yang Feng <yangfeng@kylinos.cn>

Stmmac+RTL8211F cannot set network wake-up, add related functions
- read: ethtool NETDEV
- write: ethtool -s NETDEV wol g/d

Signed-off-by: Yang Feng <yangfeng@kylinos.cn>
---
 drivers/net/phy/realtek.c | 73 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

Comments

Andrew Lunn June 2, 2024, 2:21 p.m. UTC | #1
On Sun, Jun 02, 2024 at 04:46:57PM +0800, yangfeng wrote:
> From: Yang Feng <yangfeng@kylinos.cn>
> 
> Stmmac+RTL8211F cannot set network wake-up, add related functions
> - read: ethtool NETDEV
> - write: ethtool -s NETDEV wol g/d

I don't see any interrupt handling here. How does the wake up actually
happen on your board? Is a pin of the PHY connected to a PMU? Maybe
the more normal way is that the PHY interrupt pin is used to
GPIO/interrupt controller which can wake the system. But that often
requires enabling the interrupt.

It would be good to document how it works for your board. That will
help others who need to use the interrupt method not break WoL for
your board.

       Andrew
yangfeng June 3, 2024, 3:32 p.m. UTC | #2
The RTL8211F series can monitor the network for a link change event, 
a Wake-Up Frame, or a Magic  Packet, and notify the system via the INTB/PMEB (Power Management Event; ‘B’ means low active) pin  
when such a packet or event occurs. The system can then be restored to a normal state to process incoming  jobs. 
The INTB/PMEB pin needs to be connected with a 4.7k ohm resistor and pulled up to 3.3V. 
When  the Wake-Up Frame or a Magic Packet is sent to the PHY, the INTB/PMEB pin will be set low to notify  the system to wake up. 


For example,
 1.Set MAC Address Page 0x0d8c, Reg16~Reg18 
 2.Set Max packet length Page 0xd8a, Reg17 = 0x9fff
 3.WOL event select and enable Page 0x0d8a Reg16 =  0x1000 //enable Magic Packet Event

Kind regards,
Yang Feng
diff mbox series

Patch

diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 7ab41f95dae5..2378202e6d5c 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -13,6 +13,7 @@ 
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/etherdevice.h>
 
 #define RTL821x_PHYSR				0x11
 #define RTL821x_PHYSR_DUPLEX			BIT(13)
@@ -87,6 +88,11 @@ 
 #define RTL_8221B_VN_CG				0x001cc84a
 #define RTL_8251B				0x001cc862
 
+#define RTL8211F_MAC_ADDR_32_47_OFFSET		16
+#define RTL8211F_MAC_ADDR_16_31_OFFSET		17
+#define RTL8211F_MAC_ADDR_0_15_OFFSET		18
+#define RTL8211F_MAGIC_EN			BIT(12)
+
 MODULE_DESCRIPTION("Realtek PHY driver");
 MODULE_AUTHOR("Johnson Leung");
 MODULE_LICENSE("GPL");
@@ -1109,6 +1115,71 @@  static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev)
 	return IRQ_HANDLED;
 }
 
+static int rtl821x_set_wol(struct phy_device *phydev,
+			   struct ethtool_wolinfo *wol)
+{
+	int err = 0;
+	int val = 0;
+
+	err = phy_read_paged(phydev, 0xd8a, 0x10);
+	if (err < 0)
+		return err;
+
+	if (wol->wolopts & WAKE_MAGIC) {
+		struct net_device *ndev = phydev->attached_dev;
+		const u8 *mac;
+		unsigned int i;
+		static const unsigned int offsets[] = {
+			RTL8211F_MAC_ADDR_32_47_OFFSET,
+			RTL8211F_MAC_ADDR_16_31_OFFSET,
+			RTL8211F_MAC_ADDR_0_15_OFFSET,
+		};
+
+		if (!ndev)
+			return -ENODEV;
+
+		mac = (const u8 *)ndev->dev_addr;
+
+		if (!is_valid_ether_addr(mac))
+			return -EINVAL;
+
+		for (i = 0; i < 3; i++)
+			phy_write_paged(phydev, 0xd8c, offsets[i],
+				      mac[(i * 2)] | (mac[(i * 2) + 1] << 8));
+
+		val = err | RTL8211F_MAGIC_EN;
+
+		phy_write_paged(phydev, 0xd8a, 0x11, 0x9fff);
+		err = phy_write_paged(phydev, 0xd8a, 0x10, val);
+		if (err < 0)
+			return err;
+
+	} else {
+		val = err & ~RTL8211F_MAGIC_EN;
+		err = phy_write_paged(phydev, 0xd8a, 0x10, val);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static void rtl821x_get_wol(struct phy_device *phydev,
+			   struct ethtool_wolinfo *wol)
+{
+	int value;
+
+	wol->supported = WAKE_MAGIC;
+	wol->wolopts = 0;
+
+	value = phy_read_paged(phydev, 0xd8a, 0x10);
+	if (value < 0)
+		return;
+
+	if (value & RTL8211F_MAGIC_EN)
+		wol->wolopts |= WAKE_MAGIC;
+}
+
 static struct phy_driver realtek_drvs[] = {
 	{
 		PHY_ID_MATCH_EXACT(0x00008201),
@@ -1179,6 +1250,8 @@  static struct phy_driver realtek_drvs[] = {
 		.resume		= genphy_resume,
 		.read_page	= rtl821x_read_page,
 		.write_page	= rtl821x_write_page,
+		.get_wol	= rtl821x_get_wol,
+		.set_wol	= rtl821x_set_wol,
 	}, {
 		PHY_ID_MATCH_EXACT(0x001cc916),
 		.name		= "RTL8211F Gigabit Ethernet",