From 0595f01e280d1f0943ab1dc88e5d16f2ba435426 Mon Sep 17 00:00:00 2001 From: Dongjin Kim Date: Thu, 15 Jul 2021 19:32:42 +0900 Subject: [PATCH 64/75] ODROID-COMMON: phy/realtek: add Wake-on-Lan to Realtek PHY Wake-On-Lan can set with 'ethtool' $ sudo ethtool -s eth0 wol g Check if 'Wake-on' is set with 'g' $ sudo ethtool eth0 | grep Wake Supports Wake-on: ug Wake-on: g In order to wake from remote, run 'wakeonlan' with IP address: $ wakeonlan 00:1e:06:42:45:32 Change-Id: Ida2e9ac5ce623fceecc7d00c712f173bca16e322 Signed-off-by: Dongjin Kim --- .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 + drivers/net/phy/realtek.c | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index d89455803bed..439be5b6590d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -749,6 +749,8 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) disable_irq_wake(priv->wol_irq); } + phylink_ethtool_set_wol(priv->phylink, wol); + mutex_lock(&priv->lock); priv->wolopts = wol->wolopts; mutex_unlock(&priv->lock); diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 11be60333fa8..dd82045b5ef3 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #define RTL821x_PHYSR 0x11 #define RTL821x_PHYSR_DUPLEX BIT(13) @@ -300,6 +302,51 @@ static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } +static int rtl8211f_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct net_device *ndev = phydev->attached_dev; + const u8 *mac; + int val; + + if (wol->wolopts & WAKE_MAGIC) { + mac = (const u8 *)ndev->dev_addr; + + if (!is_valid_ether_addr(mac)) + return -EINVAL; + + /* Set MAC address */ + phy_write(phydev, RTL821x_PAGE_SELECT, 0xd8c); + phy_write(phydev, 0x10, (mac[1] << 8) | mac[0]); + phy_write(phydev, 0x11, (mac[3] << 8) | mac[2]); + phy_write(phydev, 0x12, (mac[5] << 8) | mac[4]); + + phy_write(phydev, RTL821x_PAGE_SELECT, 0xd8a); + + /* Set magic packet for WOL */ + phy_write(phydev, 0x10, 0x1000); + phy_write(phydev, 0x11, 0x9fff); + + /* PIN31 - pull high */ + phy_write(phydev, RTL821x_PAGE_SELECT, 0xd40); + val = phy_read(phydev, 0x16); + phy_write(phydev, 0x16, val | BIT(5)); + + phy_write(phydev, RTL821x_PAGE_SELECT, 0); + } else { + phy_write(phydev, RTL821x_PAGE_SELECT, 0xd8a); + + /* Reset magic packet for WOL */ + phy_write(phydev, 0x10, 0x0); + val = phy_read(phydev, 0x11); + phy_write(phydev, 0x11, val & ~BIT(15)); + + phy_write(phydev, RTL821x_PAGE_SELECT, 0); + } + + return 0; +} + static int rtl8211_config_aneg(struct phy_device *phydev) { int ret; @@ -909,6 +956,7 @@ static struct phy_driver realtek_drvs[] = { .handle_interrupt = rtl821x_handle_interrupt, .suspend = genphy_suspend, .resume = genphy_resume, + .set_wol = rtl8211f_set_wol, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, }, { -- 2.25.1