r8152: support WOL

Support WOL for RTL8152 and RTL8153.

Signed-off-by: Hayes Wang <hayeswang@realtek.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
hayeswang 2014-02-18 21:49:06 +08:00 committed by David S. Miller
parent 7e9da48161
commit 21ff2e8976

View File

@ -23,7 +23,7 @@
#include <linux/ipv6.h>
/* Version Information */
#define DRIVER_VERSION "v1.04.0 (2014/01/15)"
#define DRIVER_VERSION "v1.05.0 (2014/02/18)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
#define MODULENAME "r8152"
@ -62,6 +62,8 @@
#define PLA_RSTTELLY 0xe800
#define PLA_CR 0xe813
#define PLA_CRWECR 0xe81c
#define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */
#define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */
#define PLA_CONFIG5 0xe822
#define PLA_PHY_PWR 0xe84c
#define PLA_OOB_CTRL 0xe84f
@ -216,7 +218,14 @@
/* PAL_BDC_CR */
#define ALDPS_PROXY_MODE 0x0001
/* PLA_CONFIG34 */
#define LINK_ON_WAKE_EN 0x0010
#define LINK_OFF_WAKE_EN 0x0008
/* PLA_CONFIG5 */
#define BWF_EN 0x0040
#define MWF_EN 0x0020
#define UWF_EN 0x0010
#define LAN_WAKE_EN 0x0002
/* PLA_LED_FEATURE */
@ -521,6 +530,7 @@ struct r8152 {
} rtl_ops;
int intr_interval;
u32 saved_wolopts;
u32 msg_enable;
u32 tx_qlen;
u16 ocp_base;
@ -1798,6 +1808,74 @@ static void r8152_power_cut_en(struct r8152 *tp, bool enable)
}
#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
static u32 __rtl_get_wol(struct r8152 *tp)
{
u32 ocp_data;
u32 wolopts = 0;
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5);
if (!(ocp_data & LAN_WAKE_EN))
return 0;
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
if (ocp_data & LINK_ON_WAKE_EN)
wolopts |= WAKE_PHY;
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
if (ocp_data & UWF_EN)
wolopts |= WAKE_UCAST;
if (ocp_data & BWF_EN)
wolopts |= WAKE_BCAST;
if (ocp_data & MWF_EN)
wolopts |= WAKE_MCAST;
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
if (ocp_data & MAGIC_EN)
wolopts |= WAKE_MAGIC;
return wolopts;
}
static void __rtl_set_wol(struct r8152 *tp, u32 wolopts)
{
u32 ocp_data;
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
ocp_data &= ~LINK_ON_WAKE_EN;
if (wolopts & WAKE_PHY)
ocp_data |= LINK_ON_WAKE_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN | LAN_WAKE_EN);
if (wolopts & WAKE_UCAST)
ocp_data |= UWF_EN;
if (wolopts & WAKE_BCAST)
ocp_data |= BWF_EN;
if (wolopts & WAKE_MCAST)
ocp_data |= MWF_EN;
if (wolopts & WAKE_ANY)
ocp_data |= LAN_WAKE_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
ocp_data &= ~MAGIC_EN;
if (wolopts & WAKE_MAGIC)
ocp_data |= MAGIC_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
if (wolopts & WAKE_ANY)
device_set_wakeup_enable(&tp->udev->dev, true);
else
device_set_wakeup_enable(&tp->udev->dev, false);
}
static void rtl_phy_reset(struct r8152 *tp)
{
u16 data;
@ -2002,10 +2080,6 @@ static void r8152b_enter_oob(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
ocp_data |= MAGIC_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
ocp_data |= CPCR_RX_VLAN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
@ -2018,8 +2092,6 @@ static void r8152b_enter_oob(struct r8152 *tp)
ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN);
rxdy_gated_en(tp, false);
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@ -2217,10 +2289,6 @@ static void r8153_enter_oob(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
ocp_data |= MAGIC_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
ocp_data &= ~TEREDO_WAKE_MASK;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
@ -2237,8 +2305,6 @@ static void r8153_enter_oob(struct r8152 *tp)
ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN);
rxdy_gated_en(tp, false);
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@ -2652,6 +2718,24 @@ static int rtl8152_resume(struct usb_interface *intf)
return 0;
}
static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct r8152 *tp = netdev_priv(dev);
wol->supported = WAKE_ANY;
wol->wolopts = __rtl_get_wol(tp);
}
static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct r8152 *tp = netdev_priv(dev);
__rtl_set_wol(tp, wol->wolopts);
tp->saved_wolopts = wol->wolopts & WAKE_ANY;
return 0;
}
static void rtl8152_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
@ -2685,6 +2769,8 @@ static struct ethtool_ops ops = {
.get_settings = rtl8152_get_settings,
.set_settings = rtl8152_set_settings,
.get_link = ethtool_op_get_link,
.get_wol = rtl8152_get_wol,
.set_wol = rtl8152_set_wol,
};
static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@ -2888,6 +2974,12 @@ static int rtl8152_probe(struct usb_interface *intf,
goto out1;
}
tp->saved_wolopts = __rtl_get_wol(tp);
if (tp->saved_wolopts)
device_set_wakeup_enable(&udev->dev, true);
else
device_set_wakeup_enable(&udev->dev, false);
netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
return 0;