mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									7e9da48161
								
							
						
					
					
						commit
						21ff2e8976
					
				
					 1 changed files with 105 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue