NVIDIA: SAUCE: net: phy: realtek: Enable WoL.

BugLink: https://bugs.launchpad.net/bugs/2072591

Enable WoL for RTL 8211F PHY with Magic Packet.

http://nvbugs/200562291

Signed-off-by: Gaurav Asati <gasati@nvidia.com>
Signed-off-by: Revanth Kumar Uppala <ruppala@nvidia.com>
Tested-by: Abhilash G <abhilashg@nvidia.com>
Reviewed-by: Abhilash G <abhilashg@nvidia.com>
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Acked-by: Noah Wager <noah.wager@canonical.com>
Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
Gaurav Asati
2020-12-21 13:19:09 +05:30
committed by Noah Wager
parent ff5097ef2a
commit 01de2c3559
+115 -1
View File
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/netdevice.h>
#define RTL821x_PHYSR 0x11
#define RTL821x_PHYSR_DUPLEX BIT(13)
@@ -84,6 +85,31 @@
#define RTL8211F_PAGE_LCR_LED_CONTROL 0x10
#define RTL8211F_PAGE_EEE_LED_CONTROL 0x11
#define RTL8211F_INTERRUPT_SELECT_PAGE 0xd40
#define RTL8211F_WOL_FRAME_SELECT_PAGE 0xd80
#define RTL8211F_WOL_MAC_PAGE 0xd8c
#define RTL8211F_WOL_SETTING_PAGE 0xd8a
#define RTL8211F_INTERRUPT_SELECT_REG 0x16
#define RTL8211F_WOL_REG_MAC_WORD_0 0x10
#define RTL8211F_WOL_REG_MAC_WORD_1 0x11
#define RTL8211F_WOL_REG_MAC_WORD_2 0x12
#define RTL8211F_WOL_REG_PACKET_LEN 0x11
#define RTL8211F_WOL_REG_FRAME_EVENT 0x10
#define RTL8211F_WOL_PACKET_LEN 0x1fff
#define RTL8211F_WOL_SET_PACKET_LEN BIT(15)
#define RTL8211F_WOL_ENABLE_MAGIC_PACKET BIT(12)
#define RTL8211F_WOL_ENABLE_PMEB_EVENT BIT(7)
#define BIT_SHIFT_8 8
#define MAC_ADDRESS_BYTE_0 0
#define MAC_ADDRESS_BYTE_1 1
#define MAC_ADDRESS_BYTE_2 2
#define MAC_ADDRESS_BYTE_3 3
#define MAC_ADDRESS_BYTE_4 4
#define MAC_ADDRESS_BYTE_5 5
MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
MODULE_LICENSE("GPL");
@@ -95,6 +121,36 @@ struct rtl821x_priv {
struct clk *clk;
};
static int rtl8211f_wol_settings(struct phy_device *phydev, bool enable)
{
int ret;
/* Set WoL events and packet length */
if (enable) {
ret = phy_modify_paged_changed(phydev, RTL8211F_WOL_SETTING_PAGE, RTL8211F_WOL_REG_PACKET_LEN, 0x0,
(RTL8211F_WOL_PACKET_LEN |
RTL8211F_WOL_SET_PACKET_LEN));
if (ret)
return ret;
ret = phy_modify_paged_changed(phydev, RTL8211F_WOL_SETTING_PAGE, RTL8211F_WOL_REG_FRAME_EVENT, 0x0,
RTL8211F_WOL_ENABLE_MAGIC_PACKET);
if (ret)
return ret;
} else {
ret = phy_modify_paged_changed(phydev, RTL8211F_WOL_SETTING_PAGE, RTL8211F_WOL_REG_PACKET_LEN, 0x0,
RTL8211F_WOL_PACKET_LEN);
if (ret)
return ret;
ret = phy_modify_paged_changed(phydev, RTL8211F_WOL_SETTING_PAGE, RTL8211F_WOL_REG_FRAME_EVENT, 0x0, 0x0);
if (ret)
return ret;
}
return 0;
}
static int rtl821x_read_page(struct phy_device *phydev)
{
return __phy_read(phydev, RTL821x_PAGE_SELECT);
@@ -250,7 +306,7 @@ static int rtl8211f_config_intr(struct phy_device *phydev)
if (err)
return err;
val = RTL8211F_INER_LINK_STATUS;
val = (RTL8211F_INER_LINK_STATUS | RTL8211F_WOL_ENABLE_PMEB_EVENT);
err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
} else {
val = 0;
@@ -463,6 +519,27 @@ static int rtl8211f_config_init(struct phy_device *phydev)
linkmode_set_bit(SUPPORTED_Asym_Pause, phydev->supported);
linkmode_copy(phydev->advertising, phydev->supported);
ret = phy_modify_paged_changed(phydev, RTL8211F_WOL_MAC_PAGE, RTL8211F_WOL_REG_MAC_WORD_0, 0x0,
phydev->attached_dev->dev_addr[MAC_ADDRESS_BYTE_0] |
(phydev->attached_dev->dev_addr[MAC_ADDRESS_BYTE_1]
<< BIT_SHIFT_8));
if (ret)
return ret;
ret = phy_modify_paged_changed(phydev, RTL8211F_WOL_MAC_PAGE, RTL8211F_WOL_REG_MAC_WORD_1, 0x0,
phydev->attached_dev->dev_addr[MAC_ADDRESS_BYTE_2] |
(phydev->attached_dev->dev_addr[MAC_ADDRESS_BYTE_3]
<< BIT_SHIFT_8));
if (ret)
return ret;
ret = phy_modify_paged_changed(phydev, RTL8211F_WOL_MAC_PAGE, RTL8211F_WOL_REG_MAC_WORD_2, 0x0,
phydev->attached_dev->dev_addr[MAC_ADDRESS_BYTE_4] |
(phydev->attached_dev->dev_addr[MAC_ADDRESS_BYTE_5]
<< BIT_SHIFT_8));
if (ret)
return ret;
return genphy_soft_reset(phydev);
}
@@ -917,6 +994,40 @@ static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev)
return IRQ_HANDLED;
}
static void rtl8211f_get_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{
u32 value;
/* For RTL 8211F Magic packet WoL is enabled by default */
wol->supported = WAKE_MAGIC;
value = phy_read_paged(phydev, RTL8211F_WOL_SETTING_PAGE, RTL8211F_WOL_REG_FRAME_EVENT);
if (value < 0)
return;
if (value & RTL8211F_WOL_ENABLE_MAGIC_PACKET)
wol->wolopts = WAKE_MAGIC;
}
static int rtl8211f_set_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{
int ret;
if (wol->wolopts & WAKE_MAGIC) {
ret = rtl8211f_wol_settings(phydev, true);
if (ret < 0)
return ret;
} else {
ret = rtl8211f_wol_settings(phydev, false);
if (ret < 0)
return ret;
}
return 0;
}
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -995,7 +1106,10 @@ static struct phy_driver realtek_drvs[] = {
.read_status = rtlgen_read_status,
.config_intr = &rtl8211f_config_intr,
.handle_interrupt = rtl8211f_handle_interrupt,
.get_wol = &rtl8211f_get_wol,
.set_wol = &rtl8211f_set_wol,
.suspend = rtl821x_suspend,
.suspend = genphy_suspend,
.resume = rtl821x_resume,
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,