xref: /linux/drivers/net/usb/smsc75xx.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2d0cad871SSteve Glendinning  /***************************************************************************
3d0cad871SSteve Glendinning  *
4d0cad871SSteve Glendinning  * Copyright (C) 2007-2010 SMSC
5d0cad871SSteve Glendinning  *
6d0cad871SSteve Glendinning  *****************************************************************************/
7d0cad871SSteve Glendinning 
8d0cad871SSteve Glendinning #include <linux/module.h>
9d0cad871SSteve Glendinning #include <linux/kmod.h>
10d0cad871SSteve Glendinning #include <linux/netdevice.h>
11d0cad871SSteve Glendinning #include <linux/etherdevice.h>
12d0cad871SSteve Glendinning #include <linux/ethtool.h>
13d0cad871SSteve Glendinning #include <linux/mii.h>
14d0cad871SSteve Glendinning #include <linux/usb.h>
15899a391bSSteve Glendinning #include <linux/bitrev.h>
16899a391bSSteve Glendinning #include <linux/crc16.h>
17d0cad871SSteve Glendinning #include <linux/crc32.h>
18d0cad871SSteve Glendinning #include <linux/usb/usbnet.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
20c489565bSArnd Bergmann #include <linux/of_net.h>
21d0cad871SSteve Glendinning #include "smsc75xx.h"
22d0cad871SSteve Glendinning 
23d0cad871SSteve Glendinning #define SMSC_CHIPNAME			"smsc75xx"
24d0cad871SSteve Glendinning #define SMSC_DRIVER_VERSION		"1.0.0"
25d0cad871SSteve Glendinning #define HS_USB_PKT_SIZE			(512)
26d0cad871SSteve Glendinning #define FS_USB_PKT_SIZE			(64)
27d0cad871SSteve Glendinning #define DEFAULT_HS_BURST_CAP_SIZE	(16 * 1024 + 5 * HS_USB_PKT_SIZE)
28d0cad871SSteve Glendinning #define DEFAULT_FS_BURST_CAP_SIZE	(6 * 1024 + 33 * FS_USB_PKT_SIZE)
29d0cad871SSteve Glendinning #define DEFAULT_BULK_IN_DELAY		(0x00002000)
30d0cad871SSteve Glendinning #define MAX_SINGLE_PACKET_SIZE		(9000)
31d0cad871SSteve Glendinning #define LAN75XX_EEPROM_MAGIC		(0x7500)
32d0cad871SSteve Glendinning #define EEPROM_MAC_OFFSET		(0x01)
33d0cad871SSteve Glendinning #define DEFAULT_TX_CSUM_ENABLE		(true)
34d0cad871SSteve Glendinning #define DEFAULT_RX_CSUM_ENABLE		(true)
35d0cad871SSteve Glendinning #define SMSC75XX_INTERNAL_PHY_ID	(1)
36d0cad871SSteve Glendinning #define SMSC75XX_TX_OVERHEAD		(8)
37d0cad871SSteve Glendinning #define MAX_RX_FIFO_SIZE		(20 * 1024)
38d0cad871SSteve Glendinning #define MAX_TX_FIFO_SIZE		(12 * 1024)
39d0cad871SSteve Glendinning #define USB_VENDOR_ID_SMSC		(0x0424)
40d0cad871SSteve Glendinning #define USB_PRODUCT_ID_LAN7500		(0x7500)
41d0cad871SSteve Glendinning #define USB_PRODUCT_ID_LAN7505		(0x7505)
42ea1649deSNico Erfurth #define RXW_PADDING			2
43f329ccdcSSteve Glendinning #define SUPPORTED_WAKE			(WAKE_PHY | WAKE_UCAST | WAKE_BCAST | \
44899a391bSSteve Glendinning 					 WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)
45d0cad871SSteve Glendinning 
46b4cdea9cSSteve Glendinning #define SUSPEND_SUSPEND0		(0x01)
47b4cdea9cSSteve Glendinning #define SUSPEND_SUSPEND1		(0x02)
48b4cdea9cSSteve Glendinning #define SUSPEND_SUSPEND2		(0x04)
49b4cdea9cSSteve Glendinning #define SUSPEND_SUSPEND3		(0x08)
50b4cdea9cSSteve Glendinning #define SUSPEND_ALLMODES		(SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
51b4cdea9cSSteve Glendinning 					 SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
52b4cdea9cSSteve Glendinning 
53d0cad871SSteve Glendinning struct smsc75xx_priv {
54d0cad871SSteve Glendinning 	struct usbnet *dev;
55d0cad871SSteve Glendinning 	u32 rfe_ctl;
566c636503SSteve Glendinning 	u32 wolopts;
57d0cad871SSteve Glendinning 	u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN];
58d0cad871SSteve Glendinning 	struct mutex dataport_mutex;
59d0cad871SSteve Glendinning 	spinlock_t rfe_ctl_lock;
60d0cad871SSteve Glendinning 	struct work_struct set_multicast;
61b4cdea9cSSteve Glendinning 	u8 suspend_flags;
62d0cad871SSteve Glendinning };
63d0cad871SSteve Glendinning 
64eb939922SRusty Russell static bool turbo_mode = true;
65d0cad871SSteve Glendinning module_param(turbo_mode, bool, 0644);
66d0cad871SSteve Glendinning MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
67d0cad871SSteve Glendinning 
68d461e3daSYuiko Oshino static int smsc75xx_link_ok_nopm(struct usbnet *dev);
69d461e3daSYuiko Oshino static int smsc75xx_phy_gig_workaround(struct usbnet *dev);
70d461e3daSYuiko Oshino 
__smsc75xx_read_reg(struct usbnet * dev,u32 index,u32 * data,int in_pm)7147bbea41SMing Lei static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
7247bbea41SMing Lei 					    u32 *data, int in_pm)
73d0cad871SSteve Glendinning {
742b2e41e3SMing Lei 	u32 buf;
75d0cad871SSteve Glendinning 	int ret;
7647bbea41SMing Lei 	int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
77d0cad871SSteve Glendinning 
78d0cad871SSteve Glendinning 	BUG_ON(!dev);
79d0cad871SSteve Glendinning 
8047bbea41SMing Lei 	if (!in_pm)
8147bbea41SMing Lei 		fn = usbnet_read_cmd;
8247bbea41SMing Lei 	else
8347bbea41SMing Lei 		fn = usbnet_read_cmd_nopm;
8447bbea41SMing Lei 
8547bbea41SMing Lei 	ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN
8647bbea41SMing Lei 		 | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
872b2e41e3SMing Lei 		 0, index, &buf, 4);
88e9c65989SShigeru Yoshida 	if (unlikely(ret < 4)) {
89e9c65989SShigeru Yoshida 		ret = ret < 0 ? ret : -ENODATA;
90e9c65989SShigeru Yoshida 
911e1d7412SJoe Perches 		netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n",
921e1d7412SJoe Perches 			    index, ret);
9358ef6a3fSDan Carpenter 		return ret;
9458ef6a3fSDan Carpenter 	}
95d0cad871SSteve Glendinning 
962b2e41e3SMing Lei 	le32_to_cpus(&buf);
972b2e41e3SMing Lei 	*data = buf;
98d0cad871SSteve Glendinning 
99d0cad871SSteve Glendinning 	return ret;
100d0cad871SSteve Glendinning }
101d0cad871SSteve Glendinning 
__smsc75xx_write_reg(struct usbnet * dev,u32 index,u32 data,int in_pm)10247bbea41SMing Lei static int __must_check __smsc75xx_write_reg(struct usbnet *dev, u32 index,
10347bbea41SMing Lei 					     u32 data, int in_pm)
104d0cad871SSteve Glendinning {
1052b2e41e3SMing Lei 	u32 buf;
106d0cad871SSteve Glendinning 	int ret;
10747bbea41SMing Lei 	int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
108d0cad871SSteve Glendinning 
109d0cad871SSteve Glendinning 	BUG_ON(!dev);
110d0cad871SSteve Glendinning 
11147bbea41SMing Lei 	if (!in_pm)
11247bbea41SMing Lei 		fn = usbnet_write_cmd;
11347bbea41SMing Lei 	else
11447bbea41SMing Lei 		fn = usbnet_write_cmd_nopm;
11547bbea41SMing Lei 
1162b2e41e3SMing Lei 	buf = data;
1172b2e41e3SMing Lei 	cpu_to_le32s(&buf);
118d0cad871SSteve Glendinning 
11947bbea41SMing Lei 	ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT
12047bbea41SMing Lei 		 | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1212b2e41e3SMing Lei 		 0, index, &buf, 4);
122d0cad871SSteve Glendinning 	if (unlikely(ret < 0))
1231e1d7412SJoe Perches 		netdev_warn(dev->net, "Failed to write reg index 0x%08x: %d\n",
1241e1d7412SJoe Perches 			    index, ret);
125d0cad871SSteve Glendinning 
126d0cad871SSteve Glendinning 	return ret;
127d0cad871SSteve Glendinning }
128d0cad871SSteve Glendinning 
smsc75xx_read_reg_nopm(struct usbnet * dev,u32 index,u32 * data)12947bbea41SMing Lei static int __must_check smsc75xx_read_reg_nopm(struct usbnet *dev, u32 index,
13047bbea41SMing Lei 					       u32 *data)
13147bbea41SMing Lei {
13247bbea41SMing Lei 	return __smsc75xx_read_reg(dev, index, data, 1);
13347bbea41SMing Lei }
13447bbea41SMing Lei 
smsc75xx_write_reg_nopm(struct usbnet * dev,u32 index,u32 data)13547bbea41SMing Lei static int __must_check smsc75xx_write_reg_nopm(struct usbnet *dev, u32 index,
13647bbea41SMing Lei 						u32 data)
13747bbea41SMing Lei {
13847bbea41SMing Lei 	return __smsc75xx_write_reg(dev, index, data, 1);
13947bbea41SMing Lei }
14047bbea41SMing Lei 
smsc75xx_read_reg(struct usbnet * dev,u32 index,u32 * data)14147bbea41SMing Lei static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index,
14247bbea41SMing Lei 					  u32 *data)
14347bbea41SMing Lei {
14447bbea41SMing Lei 	return __smsc75xx_read_reg(dev, index, data, 0);
14547bbea41SMing Lei }
14647bbea41SMing Lei 
smsc75xx_write_reg(struct usbnet * dev,u32 index,u32 data)14747bbea41SMing Lei static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index,
14847bbea41SMing Lei 					   u32 data)
14947bbea41SMing Lei {
15047bbea41SMing Lei 	return __smsc75xx_write_reg(dev, index, data, 0);
15147bbea41SMing Lei }
15247bbea41SMing Lei 
153d0cad871SSteve Glendinning /* Loop until the read is completed with timeout
154d0cad871SSteve Glendinning  * called with phy_mutex held */
__smsc75xx_phy_wait_not_busy(struct usbnet * dev,int in_pm)155f329ccdcSSteve Glendinning static __must_check int __smsc75xx_phy_wait_not_busy(struct usbnet *dev,
156f329ccdcSSteve Glendinning 						     int in_pm)
157d0cad871SSteve Glendinning {
158d0cad871SSteve Glendinning 	unsigned long start_time = jiffies;
159d0cad871SSteve Glendinning 	u32 val;
160d0cad871SSteve Glendinning 	int ret;
161d0cad871SSteve Glendinning 
162d0cad871SSteve Glendinning 	do {
163f329ccdcSSteve Glendinning 		ret = __smsc75xx_read_reg(dev, MII_ACCESS, &val, in_pm);
164e3c678e6SSteve Glendinning 		if (ret < 0) {
165e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading MII_ACCESS\n");
166e3c678e6SSteve Glendinning 			return ret;
167e3c678e6SSteve Glendinning 		}
168d0cad871SSteve Glendinning 
169d0cad871SSteve Glendinning 		if (!(val & MII_ACCESS_BUSY))
170d0cad871SSteve Glendinning 			return 0;
171d0cad871SSteve Glendinning 	} while (!time_after(jiffies, start_time + HZ));
172d0cad871SSteve Glendinning 
173d0cad871SSteve Glendinning 	return -EIO;
174d0cad871SSteve Glendinning }
175d0cad871SSteve Glendinning 
__smsc75xx_mdio_read(struct net_device * netdev,int phy_id,int idx,int in_pm)176f329ccdcSSteve Glendinning static int __smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx,
177f329ccdcSSteve Glendinning 				int in_pm)
178d0cad871SSteve Glendinning {
179d0cad871SSteve Glendinning 	struct usbnet *dev = netdev_priv(netdev);
180d0cad871SSteve Glendinning 	u32 val, addr;
181d0cad871SSteve Glendinning 	int ret;
182d0cad871SSteve Glendinning 
183d0cad871SSteve Glendinning 	mutex_lock(&dev->phy_mutex);
184d0cad871SSteve Glendinning 
185d0cad871SSteve Glendinning 	/* confirm MII not busy */
186f329ccdcSSteve Glendinning 	ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
187e3c678e6SSteve Glendinning 	if (ret < 0) {
188e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "MII is busy in smsc75xx_mdio_read\n");
189e3c678e6SSteve Glendinning 		goto done;
190e3c678e6SSteve Glendinning 	}
191d0cad871SSteve Glendinning 
192d0cad871SSteve Glendinning 	/* set the address, index & direction (read from PHY) */
193d0cad871SSteve Glendinning 	phy_id &= dev->mii.phy_id_mask;
194d0cad871SSteve Glendinning 	idx &= dev->mii.reg_num_mask;
195d0cad871SSteve Glendinning 	addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR)
196d0cad871SSteve Glendinning 		| ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
197cb8722d3SSteve Glendinning 		| MII_ACCESS_READ | MII_ACCESS_BUSY;
198f329ccdcSSteve Glendinning 	ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm);
199e3c678e6SSteve Glendinning 	if (ret < 0) {
200e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing MII_ACCESS\n");
201e3c678e6SSteve Glendinning 		goto done;
202e3c678e6SSteve Glendinning 	}
203d0cad871SSteve Glendinning 
204f329ccdcSSteve Glendinning 	ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
205e3c678e6SSteve Glendinning 	if (ret < 0) {
206e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx);
207e3c678e6SSteve Glendinning 		goto done;
208e3c678e6SSteve Glendinning 	}
209d0cad871SSteve Glendinning 
210f329ccdcSSteve Glendinning 	ret = __smsc75xx_read_reg(dev, MII_DATA, &val, in_pm);
211e3c678e6SSteve Glendinning 	if (ret < 0) {
212e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading MII_DATA\n");
213e3c678e6SSteve Glendinning 		goto done;
214e3c678e6SSteve Glendinning 	}
215d0cad871SSteve Glendinning 
216d0cad871SSteve Glendinning 	ret = (u16)(val & 0xFFFF);
217d0cad871SSteve Glendinning 
218d0cad871SSteve Glendinning done:
219d0cad871SSteve Glendinning 	mutex_unlock(&dev->phy_mutex);
220d0cad871SSteve Glendinning 	return ret;
221d0cad871SSteve Glendinning }
222d0cad871SSteve Glendinning 
__smsc75xx_mdio_write(struct net_device * netdev,int phy_id,int idx,int regval,int in_pm)223f329ccdcSSteve Glendinning static void __smsc75xx_mdio_write(struct net_device *netdev, int phy_id,
224f329ccdcSSteve Glendinning 				  int idx, int regval, int in_pm)
225d0cad871SSteve Glendinning {
226d0cad871SSteve Glendinning 	struct usbnet *dev = netdev_priv(netdev);
227d0cad871SSteve Glendinning 	u32 val, addr;
228d0cad871SSteve Glendinning 	int ret;
229d0cad871SSteve Glendinning 
230d0cad871SSteve Glendinning 	mutex_lock(&dev->phy_mutex);
231d0cad871SSteve Glendinning 
232d0cad871SSteve Glendinning 	/* confirm MII not busy */
233f329ccdcSSteve Glendinning 	ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
234e3c678e6SSteve Glendinning 	if (ret < 0) {
235e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "MII is busy in smsc75xx_mdio_write\n");
236e3c678e6SSteve Glendinning 		goto done;
237e3c678e6SSteve Glendinning 	}
238d0cad871SSteve Glendinning 
239d0cad871SSteve Glendinning 	val = regval;
240f329ccdcSSteve Glendinning 	ret = __smsc75xx_write_reg(dev, MII_DATA, val, in_pm);
241e3c678e6SSteve Glendinning 	if (ret < 0) {
242e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing MII_DATA\n");
243e3c678e6SSteve Glendinning 		goto done;
244e3c678e6SSteve Glendinning 	}
245d0cad871SSteve Glendinning 
246d0cad871SSteve Glendinning 	/* set the address, index & direction (write to PHY) */
247d0cad871SSteve Glendinning 	phy_id &= dev->mii.phy_id_mask;
248d0cad871SSteve Glendinning 	idx &= dev->mii.reg_num_mask;
249d0cad871SSteve Glendinning 	addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR)
250d0cad871SSteve Glendinning 		| ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
251cb8722d3SSteve Glendinning 		| MII_ACCESS_WRITE | MII_ACCESS_BUSY;
252f329ccdcSSteve Glendinning 	ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm);
253e3c678e6SSteve Glendinning 	if (ret < 0) {
254e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing MII_ACCESS\n");
255e3c678e6SSteve Glendinning 		goto done;
256e3c678e6SSteve Glendinning 	}
257d0cad871SSteve Glendinning 
258f329ccdcSSteve Glendinning 	ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
259e3c678e6SSteve Glendinning 	if (ret < 0) {
260e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx);
261e3c678e6SSteve Glendinning 		goto done;
262e3c678e6SSteve Glendinning 	}
263d0cad871SSteve Glendinning 
264d0cad871SSteve Glendinning done:
265d0cad871SSteve Glendinning 	mutex_unlock(&dev->phy_mutex);
266d0cad871SSteve Glendinning }
267d0cad871SSteve Glendinning 
smsc75xx_mdio_read_nopm(struct net_device * netdev,int phy_id,int idx)268f329ccdcSSteve Glendinning static int smsc75xx_mdio_read_nopm(struct net_device *netdev, int phy_id,
269f329ccdcSSteve Glendinning 				   int idx)
270f329ccdcSSteve Glendinning {
271f329ccdcSSteve Glendinning 	return __smsc75xx_mdio_read(netdev, phy_id, idx, 1);
272f329ccdcSSteve Glendinning }
273f329ccdcSSteve Glendinning 
smsc75xx_mdio_write_nopm(struct net_device * netdev,int phy_id,int idx,int regval)274f329ccdcSSteve Glendinning static void smsc75xx_mdio_write_nopm(struct net_device *netdev, int phy_id,
275f329ccdcSSteve Glendinning 				     int idx, int regval)
276f329ccdcSSteve Glendinning {
277f329ccdcSSteve Glendinning 	__smsc75xx_mdio_write(netdev, phy_id, idx, regval, 1);
278f329ccdcSSteve Glendinning }
279f329ccdcSSteve Glendinning 
smsc75xx_mdio_read(struct net_device * netdev,int phy_id,int idx)280f329ccdcSSteve Glendinning static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
281f329ccdcSSteve Glendinning {
282f329ccdcSSteve Glendinning 	return __smsc75xx_mdio_read(netdev, phy_id, idx, 0);
283f329ccdcSSteve Glendinning }
284f329ccdcSSteve Glendinning 
smsc75xx_mdio_write(struct net_device * netdev,int phy_id,int idx,int regval)285f329ccdcSSteve Glendinning static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
286f329ccdcSSteve Glendinning 				int regval)
287f329ccdcSSteve Glendinning {
288f329ccdcSSteve Glendinning 	__smsc75xx_mdio_write(netdev, phy_id, idx, regval, 0);
289f329ccdcSSteve Glendinning }
290f329ccdcSSteve Glendinning 
smsc75xx_wait_eeprom(struct usbnet * dev)291d0cad871SSteve Glendinning static int smsc75xx_wait_eeprom(struct usbnet *dev)
292d0cad871SSteve Glendinning {
293d0cad871SSteve Glendinning 	unsigned long start_time = jiffies;
294d0cad871SSteve Glendinning 	u32 val;
295d0cad871SSteve Glendinning 	int ret;
296d0cad871SSteve Glendinning 
297d0cad871SSteve Glendinning 	do {
298d0cad871SSteve Glendinning 		ret = smsc75xx_read_reg(dev, E2P_CMD, &val);
299e3c678e6SSteve Glendinning 		if (ret < 0) {
300e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading E2P_CMD\n");
301e3c678e6SSteve Glendinning 			return ret;
302e3c678e6SSteve Glendinning 		}
303d0cad871SSteve Glendinning 
304d0cad871SSteve Glendinning 		if (!(val & E2P_CMD_BUSY) || (val & E2P_CMD_TIMEOUT))
305d0cad871SSteve Glendinning 			break;
306d0cad871SSteve Glendinning 		udelay(40);
307d0cad871SSteve Glendinning 	} while (!time_after(jiffies, start_time + HZ));
308d0cad871SSteve Glendinning 
309d0cad871SSteve Glendinning 	if (val & (E2P_CMD_TIMEOUT | E2P_CMD_BUSY)) {
3101e1d7412SJoe Perches 		netdev_warn(dev->net, "EEPROM read operation timeout\n");
311d0cad871SSteve Glendinning 		return -EIO;
312d0cad871SSteve Glendinning 	}
313d0cad871SSteve Glendinning 
314d0cad871SSteve Glendinning 	return 0;
315d0cad871SSteve Glendinning }
316d0cad871SSteve Glendinning 
smsc75xx_eeprom_confirm_not_busy(struct usbnet * dev)317d0cad871SSteve Glendinning static int smsc75xx_eeprom_confirm_not_busy(struct usbnet *dev)
318d0cad871SSteve Glendinning {
319d0cad871SSteve Glendinning 	unsigned long start_time = jiffies;
320d0cad871SSteve Glendinning 	u32 val;
321d0cad871SSteve Glendinning 	int ret;
322d0cad871SSteve Glendinning 
323d0cad871SSteve Glendinning 	do {
324d0cad871SSteve Glendinning 		ret = smsc75xx_read_reg(dev, E2P_CMD, &val);
325e3c678e6SSteve Glendinning 		if (ret < 0) {
326e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading E2P_CMD\n");
327e3c678e6SSteve Glendinning 			return ret;
328e3c678e6SSteve Glendinning 		}
329d0cad871SSteve Glendinning 
330d0cad871SSteve Glendinning 		if (!(val & E2P_CMD_BUSY))
331d0cad871SSteve Glendinning 			return 0;
332d0cad871SSteve Glendinning 
333d0cad871SSteve Glendinning 		udelay(40);
334d0cad871SSteve Glendinning 	} while (!time_after(jiffies, start_time + HZ));
335d0cad871SSteve Glendinning 
3361e1d7412SJoe Perches 	netdev_warn(dev->net, "EEPROM is busy\n");
337d0cad871SSteve Glendinning 	return -EIO;
338d0cad871SSteve Glendinning }
339d0cad871SSteve Glendinning 
smsc75xx_read_eeprom(struct usbnet * dev,u32 offset,u32 length,u8 * data)340d0cad871SSteve Glendinning static int smsc75xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length,
341d0cad871SSteve Glendinning 				u8 *data)
342d0cad871SSteve Glendinning {
343d0cad871SSteve Glendinning 	u32 val;
344d0cad871SSteve Glendinning 	int i, ret;
345d0cad871SSteve Glendinning 
346d0cad871SSteve Glendinning 	BUG_ON(!dev);
347d0cad871SSteve Glendinning 	BUG_ON(!data);
348d0cad871SSteve Glendinning 
349d0cad871SSteve Glendinning 	ret = smsc75xx_eeprom_confirm_not_busy(dev);
350d0cad871SSteve Glendinning 	if (ret)
351d0cad871SSteve Glendinning 		return ret;
352d0cad871SSteve Glendinning 
353d0cad871SSteve Glendinning 	for (i = 0; i < length; i++) {
354d0cad871SSteve Glendinning 		val = E2P_CMD_BUSY | E2P_CMD_READ | (offset & E2P_CMD_ADDR);
355d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, E2P_CMD, val);
356e3c678e6SSteve Glendinning 		if (ret < 0) {
357e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing E2P_CMD\n");
358e3c678e6SSteve Glendinning 			return ret;
359e3c678e6SSteve Glendinning 		}
360d0cad871SSteve Glendinning 
361d0cad871SSteve Glendinning 		ret = smsc75xx_wait_eeprom(dev);
362d0cad871SSteve Glendinning 		if (ret < 0)
363d0cad871SSteve Glendinning 			return ret;
364d0cad871SSteve Glendinning 
365d0cad871SSteve Glendinning 		ret = smsc75xx_read_reg(dev, E2P_DATA, &val);
366e3c678e6SSteve Glendinning 		if (ret < 0) {
367e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading E2P_DATA\n");
368e3c678e6SSteve Glendinning 			return ret;
369e3c678e6SSteve Glendinning 		}
370d0cad871SSteve Glendinning 
371d0cad871SSteve Glendinning 		data[i] = val & 0xFF;
372d0cad871SSteve Glendinning 		offset++;
373d0cad871SSteve Glendinning 	}
374d0cad871SSteve Glendinning 
375d0cad871SSteve Glendinning 	return 0;
376d0cad871SSteve Glendinning }
377d0cad871SSteve Glendinning 
smsc75xx_write_eeprom(struct usbnet * dev,u32 offset,u32 length,u8 * data)378d0cad871SSteve Glendinning static int smsc75xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length,
379d0cad871SSteve Glendinning 				 u8 *data)
380d0cad871SSteve Glendinning {
381d0cad871SSteve Glendinning 	u32 val;
382d0cad871SSteve Glendinning 	int i, ret;
383d0cad871SSteve Glendinning 
384d0cad871SSteve Glendinning 	BUG_ON(!dev);
385d0cad871SSteve Glendinning 	BUG_ON(!data);
386d0cad871SSteve Glendinning 
387d0cad871SSteve Glendinning 	ret = smsc75xx_eeprom_confirm_not_busy(dev);
388d0cad871SSteve Glendinning 	if (ret)
389d0cad871SSteve Glendinning 		return ret;
390d0cad871SSteve Glendinning 
391d0cad871SSteve Glendinning 	/* Issue write/erase enable command */
392d0cad871SSteve Glendinning 	val = E2P_CMD_BUSY | E2P_CMD_EWEN;
393d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, E2P_CMD, val);
394e3c678e6SSteve Glendinning 	if (ret < 0) {
395e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing E2P_CMD\n");
396e3c678e6SSteve Glendinning 		return ret;
397e3c678e6SSteve Glendinning 	}
398d0cad871SSteve Glendinning 
399d0cad871SSteve Glendinning 	ret = smsc75xx_wait_eeprom(dev);
400d0cad871SSteve Glendinning 	if (ret < 0)
401d0cad871SSteve Glendinning 		return ret;
402d0cad871SSteve Glendinning 
403d0cad871SSteve Glendinning 	for (i = 0; i < length; i++) {
404d0cad871SSteve Glendinning 
405d0cad871SSteve Glendinning 		/* Fill data register */
406d0cad871SSteve Glendinning 		val = data[i];
407d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, E2P_DATA, val);
408e3c678e6SSteve Glendinning 		if (ret < 0) {
409e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing E2P_DATA\n");
410e3c678e6SSteve Glendinning 			return ret;
411e3c678e6SSteve Glendinning 		}
412d0cad871SSteve Glendinning 
413d0cad871SSteve Glendinning 		/* Send "write" command */
414d0cad871SSteve Glendinning 		val = E2P_CMD_BUSY | E2P_CMD_WRITE | (offset & E2P_CMD_ADDR);
415d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, E2P_CMD, val);
416e3c678e6SSteve Glendinning 		if (ret < 0) {
417e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing E2P_CMD\n");
418e3c678e6SSteve Glendinning 			return ret;
419e3c678e6SSteve Glendinning 		}
420d0cad871SSteve Glendinning 
421d0cad871SSteve Glendinning 		ret = smsc75xx_wait_eeprom(dev);
422d0cad871SSteve Glendinning 		if (ret < 0)
423d0cad871SSteve Glendinning 			return ret;
424d0cad871SSteve Glendinning 
425d0cad871SSteve Glendinning 		offset++;
426d0cad871SSteve Glendinning 	}
427d0cad871SSteve Glendinning 
428d0cad871SSteve Glendinning 	return 0;
429d0cad871SSteve Glendinning }
430d0cad871SSteve Glendinning 
smsc75xx_dataport_wait_not_busy(struct usbnet * dev)431d0cad871SSteve Glendinning static int smsc75xx_dataport_wait_not_busy(struct usbnet *dev)
432d0cad871SSteve Glendinning {
433d0cad871SSteve Glendinning 	int i, ret;
434d0cad871SSteve Glendinning 
435d0cad871SSteve Glendinning 	for (i = 0; i < 100; i++) {
436d0cad871SSteve Glendinning 		u32 dp_sel;
437d0cad871SSteve Glendinning 		ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel);
438e3c678e6SSteve Glendinning 		if (ret < 0) {
439e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading DP_SEL\n");
440e3c678e6SSteve Glendinning 			return ret;
441e3c678e6SSteve Glendinning 		}
442d0cad871SSteve Glendinning 
443d0cad871SSteve Glendinning 		if (dp_sel & DP_SEL_DPRDY)
444d0cad871SSteve Glendinning 			return 0;
445d0cad871SSteve Glendinning 
446d0cad871SSteve Glendinning 		udelay(40);
447d0cad871SSteve Glendinning 	}
448d0cad871SSteve Glendinning 
4491e1d7412SJoe Perches 	netdev_warn(dev->net, "smsc75xx_dataport_wait_not_busy timed out\n");
450d0cad871SSteve Glendinning 
451d0cad871SSteve Glendinning 	return -EIO;
452d0cad871SSteve Glendinning }
453d0cad871SSteve Glendinning 
smsc75xx_dataport_write(struct usbnet * dev,u32 ram_select,u32 addr,u32 length,u32 * buf)454d0cad871SSteve Glendinning static int smsc75xx_dataport_write(struct usbnet *dev, u32 ram_select, u32 addr,
455d0cad871SSteve Glendinning 				   u32 length, u32 *buf)
456d0cad871SSteve Glendinning {
457d0cad871SSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
458d0cad871SSteve Glendinning 	u32 dp_sel;
459d0cad871SSteve Glendinning 	int i, ret;
460d0cad871SSteve Glendinning 
461d0cad871SSteve Glendinning 	mutex_lock(&pdata->dataport_mutex);
462d0cad871SSteve Glendinning 
463d0cad871SSteve Glendinning 	ret = smsc75xx_dataport_wait_not_busy(dev);
464e3c678e6SSteve Glendinning 	if (ret < 0) {
465e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "smsc75xx_dataport_write busy on entry\n");
466e3c678e6SSteve Glendinning 		goto done;
467e3c678e6SSteve Glendinning 	}
468d0cad871SSteve Glendinning 
469d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel);
470e3c678e6SSteve Glendinning 	if (ret < 0) {
471e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading DP_SEL\n");
472e3c678e6SSteve Glendinning 		goto done;
473e3c678e6SSteve Glendinning 	}
474d0cad871SSteve Glendinning 
475d0cad871SSteve Glendinning 	dp_sel &= ~DP_SEL_RSEL;
476d0cad871SSteve Glendinning 	dp_sel |= ram_select;
477d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, DP_SEL, dp_sel);
478e3c678e6SSteve Glendinning 	if (ret < 0) {
479e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing DP_SEL\n");
480e3c678e6SSteve Glendinning 		goto done;
481e3c678e6SSteve Glendinning 	}
482d0cad871SSteve Glendinning 
483d0cad871SSteve Glendinning 	for (i = 0; i < length; i++) {
484d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, DP_ADDR, addr + i);
485e3c678e6SSteve Glendinning 		if (ret < 0) {
486e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing DP_ADDR\n");
487e3c678e6SSteve Glendinning 			goto done;
488e3c678e6SSteve Glendinning 		}
489d0cad871SSteve Glendinning 
490d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, DP_DATA, buf[i]);
491e3c678e6SSteve Glendinning 		if (ret < 0) {
492e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing DP_DATA\n");
493e3c678e6SSteve Glendinning 			goto done;
494e3c678e6SSteve Glendinning 		}
495d0cad871SSteve Glendinning 
496d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, DP_CMD, DP_CMD_WRITE);
497e3c678e6SSteve Glendinning 		if (ret < 0) {
498e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing DP_CMD\n");
499e3c678e6SSteve Glendinning 			goto done;
500e3c678e6SSteve Glendinning 		}
501d0cad871SSteve Glendinning 
502d0cad871SSteve Glendinning 		ret = smsc75xx_dataport_wait_not_busy(dev);
503e3c678e6SSteve Glendinning 		if (ret < 0) {
504e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "smsc75xx_dataport_write timeout\n");
505e3c678e6SSteve Glendinning 			goto done;
506e3c678e6SSteve Glendinning 		}
507d0cad871SSteve Glendinning 	}
508d0cad871SSteve Glendinning 
509d0cad871SSteve Glendinning done:
510d0cad871SSteve Glendinning 	mutex_unlock(&pdata->dataport_mutex);
511d0cad871SSteve Glendinning 	return ret;
512d0cad871SSteve Glendinning }
513d0cad871SSteve Glendinning 
514d0cad871SSteve Glendinning /* returns hash bit number for given MAC address */
smsc75xx_hash(char addr[ETH_ALEN])515d0cad871SSteve Glendinning static u32 smsc75xx_hash(char addr[ETH_ALEN])
516d0cad871SSteve Glendinning {
517d0cad871SSteve Glendinning 	return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff;
518d0cad871SSteve Glendinning }
519d0cad871SSteve Glendinning 
smsc75xx_deferred_multicast_write(struct work_struct * param)520d0cad871SSteve Glendinning static void smsc75xx_deferred_multicast_write(struct work_struct *param)
521d0cad871SSteve Glendinning {
522d0cad871SSteve Glendinning 	struct smsc75xx_priv *pdata =
523d0cad871SSteve Glendinning 		container_of(param, struct smsc75xx_priv, set_multicast);
524d0cad871SSteve Glendinning 	struct usbnet *dev = pdata->dev;
525d0cad871SSteve Glendinning 	int ret;
526d0cad871SSteve Glendinning 
5271e1d7412SJoe Perches 	netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x\n",
528d0cad871SSteve Glendinning 		  pdata->rfe_ctl);
529d0cad871SSteve Glendinning 
530d0cad871SSteve Glendinning 	smsc75xx_dataport_write(dev, DP_SEL_VHF, DP_SEL_VHF_VLAN_LEN,
531d0cad871SSteve Glendinning 		DP_SEL_VHF_HASH_LEN, pdata->multicast_hash_table);
532d0cad871SSteve Glendinning 
533d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
534e3c678e6SSteve Glendinning 	if (ret < 0)
535e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing RFE_CRL\n");
536d0cad871SSteve Glendinning }
537d0cad871SSteve Glendinning 
smsc75xx_set_multicast(struct net_device * netdev)538d0cad871SSteve Glendinning static void smsc75xx_set_multicast(struct net_device *netdev)
539d0cad871SSteve Glendinning {
540d0cad871SSteve Glendinning 	struct usbnet *dev = netdev_priv(netdev);
541d0cad871SSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
542d0cad871SSteve Glendinning 	unsigned long flags;
543d0cad871SSteve Glendinning 	int i;
544d0cad871SSteve Glendinning 
545d0cad871SSteve Glendinning 	spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
546d0cad871SSteve Glendinning 
547d0cad871SSteve Glendinning 	pdata->rfe_ctl &=
548d0cad871SSteve Glendinning 		~(RFE_CTL_AU | RFE_CTL_AM | RFE_CTL_DPF | RFE_CTL_MHF);
549d0cad871SSteve Glendinning 	pdata->rfe_ctl |= RFE_CTL_AB;
550d0cad871SSteve Glendinning 
551d0cad871SSteve Glendinning 	for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++)
552d0cad871SSteve Glendinning 		pdata->multicast_hash_table[i] = 0;
553d0cad871SSteve Glendinning 
554d0cad871SSteve Glendinning 	if (dev->net->flags & IFF_PROMISC) {
5551e1d7412SJoe Perches 		netif_dbg(dev, drv, dev->net, "promiscuous mode enabled\n");
556d0cad871SSteve Glendinning 		pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_AU;
557d0cad871SSteve Glendinning 	} else if (dev->net->flags & IFF_ALLMULTI) {
5581e1d7412SJoe Perches 		netif_dbg(dev, drv, dev->net, "receive all multicast enabled\n");
559d0cad871SSteve Glendinning 		pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_DPF;
560d0cad871SSteve Glendinning 	} else if (!netdev_mc_empty(dev->net)) {
56122bedad3SJiri Pirko 		struct netdev_hw_addr *ha;
562d0cad871SSteve Glendinning 
5631e1d7412SJoe Perches 		netif_dbg(dev, drv, dev->net, "receive multicast hash filter\n");
564d0cad871SSteve Glendinning 
565d0cad871SSteve Glendinning 		pdata->rfe_ctl |= RFE_CTL_MHF | RFE_CTL_DPF;
566d0cad871SSteve Glendinning 
56722bedad3SJiri Pirko 		netdev_for_each_mc_addr(ha, netdev) {
56822bedad3SJiri Pirko 			u32 bitnum = smsc75xx_hash(ha->addr);
569d0cad871SSteve Glendinning 			pdata->multicast_hash_table[bitnum / 32] |=
570d0cad871SSteve Glendinning 				(1 << (bitnum % 32));
571d0cad871SSteve Glendinning 		}
572d0cad871SSteve Glendinning 	} else {
5731e1d7412SJoe Perches 		netif_dbg(dev, drv, dev->net, "receive own packets only\n");
574d0cad871SSteve Glendinning 		pdata->rfe_ctl |= RFE_CTL_DPF;
575d0cad871SSteve Glendinning 	}
576d0cad871SSteve Glendinning 
577d0cad871SSteve Glendinning 	spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
578d0cad871SSteve Glendinning 
579d0cad871SSteve Glendinning 	/* defer register writes to a sleepable context */
580d0cad871SSteve Glendinning 	schedule_work(&pdata->set_multicast);
581d0cad871SSteve Glendinning }
582d0cad871SSteve Glendinning 
smsc75xx_update_flowcontrol(struct usbnet * dev,u8 duplex,u16 lcladv,u16 rmtadv)583d0cad871SSteve Glendinning static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,
584d0cad871SSteve Glendinning 					    u16 lcladv, u16 rmtadv)
585d0cad871SSteve Glendinning {
586d0cad871SSteve Glendinning 	u32 flow = 0, fct_flow = 0;
587d0cad871SSteve Glendinning 	int ret;
588d0cad871SSteve Glendinning 
589d0cad871SSteve Glendinning 	if (duplex == DUPLEX_FULL) {
590d0cad871SSteve Glendinning 		u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
591d0cad871SSteve Glendinning 
592d0cad871SSteve Glendinning 		if (cap & FLOW_CTRL_TX) {
593d0cad871SSteve Glendinning 			flow = (FLOW_TX_FCEN | 0xFFFF);
594d0cad871SSteve Glendinning 			/* set fct_flow thresholds to 20% and 80% */
595d0cad871SSteve Glendinning 			fct_flow = (8 << 8) | 32;
596d0cad871SSteve Glendinning 		}
597d0cad871SSteve Glendinning 
598d0cad871SSteve Glendinning 		if (cap & FLOW_CTRL_RX)
599d0cad871SSteve Glendinning 			flow |= FLOW_RX_FCEN;
600d0cad871SSteve Glendinning 
6011e1d7412SJoe Perches 		netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s\n",
602d0cad871SSteve Glendinning 			  (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
603d0cad871SSteve Glendinning 			  (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
604d0cad871SSteve Glendinning 	} else {
6051e1d7412SJoe Perches 		netif_dbg(dev, link, dev->net, "half duplex\n");
606d0cad871SSteve Glendinning 	}
607d0cad871SSteve Glendinning 
608d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, FLOW, flow);
609e3c678e6SSteve Glendinning 	if (ret < 0) {
610e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing FLOW\n");
611e3c678e6SSteve Glendinning 		return ret;
612e3c678e6SSteve Glendinning 	}
613d0cad871SSteve Glendinning 
614d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, FCT_FLOW, fct_flow);
615e3c678e6SSteve Glendinning 	if (ret < 0) {
616e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing FCT_FLOW\n");
617e3c678e6SSteve Glendinning 		return ret;
618e3c678e6SSteve Glendinning 	}
619d0cad871SSteve Glendinning 
620d0cad871SSteve Glendinning 	return 0;
621d0cad871SSteve Glendinning }
622d0cad871SSteve Glendinning 
smsc75xx_link_reset(struct usbnet * dev)623d0cad871SSteve Glendinning static int smsc75xx_link_reset(struct usbnet *dev)
624d0cad871SSteve Glendinning {
625d0cad871SSteve Glendinning 	struct mii_if_info *mii = &dev->mii;
6268ae6dacaSDavid Decotigny 	struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
627d0cad871SSteve Glendinning 	u16 lcladv, rmtadv;
628d0cad871SSteve Glendinning 	int ret;
629d0cad871SSteve Glendinning 
6304f94a929SSteve Glendinning 	/* write to clear phy interrupt status */
6317749622dSSteve Glendinning 	smsc75xx_mdio_write(dev->net, mii->phy_id, PHY_INT_SRC,
6327749622dSSteve Glendinning 		PHY_INT_SRC_CLEAR_ALL);
633d0cad871SSteve Glendinning 
634d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL);
635e3c678e6SSteve Glendinning 	if (ret < 0) {
636e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing INT_STS\n");
637e3c678e6SSteve Glendinning 		return ret;
638e3c678e6SSteve Glendinning 	}
639d0cad871SSteve Glendinning 
640d0cad871SSteve Glendinning 	mii_check_media(mii, 1, 1);
641d0cad871SSteve Glendinning 	mii_ethtool_gset(&dev->mii, &ecmd);
642d0cad871SSteve Glendinning 	lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
643d0cad871SSteve Glendinning 	rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
644d0cad871SSteve Glendinning 
6451e1d7412SJoe Perches 	netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n",
6461e1d7412SJoe Perches 		  ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv);
647d0cad871SSteve Glendinning 
648d0cad871SSteve Glendinning 	return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
649d0cad871SSteve Glendinning }
650d0cad871SSteve Glendinning 
smsc75xx_status(struct usbnet * dev,struct urb * urb)651d0cad871SSteve Glendinning static void smsc75xx_status(struct usbnet *dev, struct urb *urb)
652d0cad871SSteve Glendinning {
653d0cad871SSteve Glendinning 	u32 intdata;
654d0cad871SSteve Glendinning 
655d0cad871SSteve Glendinning 	if (urb->actual_length != 4) {
6561e1d7412SJoe Perches 		netdev_warn(dev->net, "unexpected urb length %d\n",
6571e1d7412SJoe Perches 			    urb->actual_length);
658d0cad871SSteve Glendinning 		return;
659d0cad871SSteve Glendinning 	}
660d0cad871SSteve Glendinning 
6615864118bSChuhong Yuan 	intdata = get_unaligned_le32(urb->transfer_buffer);
662d0cad871SSteve Glendinning 
6631e1d7412SJoe Perches 	netif_dbg(dev, link, dev->net, "intdata: 0x%08X\n", intdata);
664d0cad871SSteve Glendinning 
665d0cad871SSteve Glendinning 	if (intdata & INT_ENP_PHY_INT)
666d0cad871SSteve Glendinning 		usbnet_defer_kevent(dev, EVENT_LINK_RESET);
667d0cad871SSteve Glendinning 	else
6681e1d7412SJoe Perches 		netdev_warn(dev->net, "unexpected interrupt, intdata=0x%08X\n",
6691e1d7412SJoe Perches 			    intdata);
670d0cad871SSteve Glendinning }
671d0cad871SSteve Glendinning 
smsc75xx_ethtool_get_eeprom_len(struct net_device * net)672d0cad871SSteve Glendinning static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net)
673d0cad871SSteve Glendinning {
674d0cad871SSteve Glendinning 	return MAX_EEPROM_SIZE;
675d0cad871SSteve Glendinning }
676d0cad871SSteve Glendinning 
smsc75xx_ethtool_get_eeprom(struct net_device * netdev,struct ethtool_eeprom * ee,u8 * data)677d0cad871SSteve Glendinning static int smsc75xx_ethtool_get_eeprom(struct net_device *netdev,
678d0cad871SSteve Glendinning 				       struct ethtool_eeprom *ee, u8 *data)
679d0cad871SSteve Glendinning {
680d0cad871SSteve Glendinning 	struct usbnet *dev = netdev_priv(netdev);
681d0cad871SSteve Glendinning 
682d0cad871SSteve Glendinning 	ee->magic = LAN75XX_EEPROM_MAGIC;
683d0cad871SSteve Glendinning 
684d0cad871SSteve Glendinning 	return smsc75xx_read_eeprom(dev, ee->offset, ee->len, data);
685d0cad871SSteve Glendinning }
686d0cad871SSteve Glendinning 
smsc75xx_ethtool_set_eeprom(struct net_device * netdev,struct ethtool_eeprom * ee,u8 * data)687d0cad871SSteve Glendinning static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev,
688d0cad871SSteve Glendinning 				       struct ethtool_eeprom *ee, u8 *data)
689d0cad871SSteve Glendinning {
690d0cad871SSteve Glendinning 	struct usbnet *dev = netdev_priv(netdev);
691d0cad871SSteve Glendinning 
692d0cad871SSteve Glendinning 	if (ee->magic != LAN75XX_EEPROM_MAGIC) {
6931e1d7412SJoe Perches 		netdev_warn(dev->net, "EEPROM: magic value mismatch: 0x%x\n",
6941e1d7412SJoe Perches 			    ee->magic);
695d0cad871SSteve Glendinning 		return -EINVAL;
696d0cad871SSteve Glendinning 	}
697d0cad871SSteve Glendinning 
698d0cad871SSteve Glendinning 	return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data);
699d0cad871SSteve Glendinning }
700d0cad871SSteve Glendinning 
smsc75xx_ethtool_get_wol(struct net_device * net,struct ethtool_wolinfo * wolinfo)7016c636503SSteve Glendinning static void smsc75xx_ethtool_get_wol(struct net_device *net,
7026c636503SSteve Glendinning 				     struct ethtool_wolinfo *wolinfo)
7036c636503SSteve Glendinning {
7046c636503SSteve Glendinning 	struct usbnet *dev = netdev_priv(net);
7056c636503SSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
7066c636503SSteve Glendinning 
7076c636503SSteve Glendinning 	wolinfo->supported = SUPPORTED_WAKE;
7086c636503SSteve Glendinning 	wolinfo->wolopts = pdata->wolopts;
7096c636503SSteve Glendinning }
7106c636503SSteve Glendinning 
smsc75xx_ethtool_set_wol(struct net_device * net,struct ethtool_wolinfo * wolinfo)7116c636503SSteve Glendinning static int smsc75xx_ethtool_set_wol(struct net_device *net,
7126c636503SSteve Glendinning 				    struct ethtool_wolinfo *wolinfo)
7136c636503SSteve Glendinning {
7146c636503SSteve Glendinning 	struct usbnet *dev = netdev_priv(net);
7156c636503SSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
716351f33d9SSteve Glendinning 	int ret;
7176c636503SSteve Glendinning 
7189c734b27SFlorian Fainelli 	if (wolinfo->wolopts & ~SUPPORTED_WAKE)
7199c734b27SFlorian Fainelli 		return -EINVAL;
7209c734b27SFlorian Fainelli 
7216c636503SSteve Glendinning 	pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
722351f33d9SSteve Glendinning 
723351f33d9SSteve Glendinning 	ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts);
724e3c678e6SSteve Glendinning 	if (ret < 0)
725e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "device_set_wakeup_enable error %d\n", ret);
726351f33d9SSteve Glendinning 
727e3c678e6SSteve Glendinning 	return ret;
7286c636503SSteve Glendinning }
7296c636503SSteve Glendinning 
730d0cad871SSteve Glendinning static const struct ethtool_ops smsc75xx_ethtool_ops = {
731d0cad871SSteve Glendinning 	.get_link	= usbnet_get_link,
732d0cad871SSteve Glendinning 	.nway_reset	= usbnet_nway_reset,
733d0cad871SSteve Glendinning 	.get_drvinfo	= usbnet_get_drvinfo,
734d0cad871SSteve Glendinning 	.get_msglevel	= usbnet_get_msglevel,
735d0cad871SSteve Glendinning 	.set_msglevel	= usbnet_set_msglevel,
736d0cad871SSteve Glendinning 	.get_eeprom_len	= smsc75xx_ethtool_get_eeprom_len,
737d0cad871SSteve Glendinning 	.get_eeprom	= smsc75xx_ethtool_get_eeprom,
738d0cad871SSteve Glendinning 	.set_eeprom	= smsc75xx_ethtool_set_eeprom,
7396c636503SSteve Glendinning 	.get_wol	= smsc75xx_ethtool_get_wol,
7406c636503SSteve Glendinning 	.set_wol	= smsc75xx_ethtool_set_wol,
74177651900SOliver Neukum 	.get_link_ksettings	= usbnet_get_link_ksettings_mii,
74277651900SOliver Neukum 	.set_link_ksettings	= usbnet_set_link_ksettings_mii,
743d0cad871SSteve Glendinning };
744d0cad871SSteve Glendinning 
smsc75xx_ioctl(struct net_device * netdev,struct ifreq * rq,int cmd)745d0cad871SSteve Glendinning static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
746d0cad871SSteve Glendinning {
747d0cad871SSteve Glendinning 	struct usbnet *dev = netdev_priv(netdev);
748d0cad871SSteve Glendinning 
749d0cad871SSteve Glendinning 	if (!netif_running(netdev))
750d0cad871SSteve Glendinning 		return -EINVAL;
751d0cad871SSteve Glendinning 
752d0cad871SSteve Glendinning 	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
753d0cad871SSteve Glendinning }
754d0cad871SSteve Glendinning 
smsc75xx_init_mac_address(struct usbnet * dev)755d0cad871SSteve Glendinning static void smsc75xx_init_mac_address(struct usbnet *dev)
756d0cad871SSteve Glendinning {
757a7021af7SJakub Kicinski 	u8 addr[ETH_ALEN];
758a7021af7SJakub Kicinski 
759c489565bSArnd Bergmann 	/* maybe the boot loader passed the MAC address in devicetree */
7604d04cdc5SJakub Kicinski 	if (!platform_get_ethdev_address(&dev->udev->dev, dev->net)) {
7614f359b65SŁukasz Stelmach 		if (is_valid_ether_addr(dev->net->dev_addr)) {
7624f359b65SŁukasz Stelmach 			/* device tree values are valid so use them */
7634f359b65SŁukasz Stelmach 			netif_dbg(dev, ifup, dev->net, "MAC address read from the device tree\n");
764c489565bSArnd Bergmann 			return;
765c489565bSArnd Bergmann 		}
7664f359b65SŁukasz Stelmach 	}
767c489565bSArnd Bergmann 
768d0cad871SSteve Glendinning 	/* try reading mac address from EEPROM */
769a7021af7SJakub Kicinski 	if (smsc75xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, addr) == 0) {
770a7021af7SJakub Kicinski 		eth_hw_addr_set(dev->net, addr);
771d0cad871SSteve Glendinning 		if (is_valid_ether_addr(dev->net->dev_addr)) {
772d0cad871SSteve Glendinning 			/* eeprom values are valid so use them */
773d0cad871SSteve Glendinning 			netif_dbg(dev, ifup, dev->net,
7741e1d7412SJoe Perches 				  "MAC address read from EEPROM\n");
775d0cad871SSteve Glendinning 			return;
776d0cad871SSteve Glendinning 		}
777d0cad871SSteve Glendinning 	}
778d0cad871SSteve Glendinning 
779c489565bSArnd Bergmann 	/* no useful static MAC address found. generate a random one */
780f2cedb63SDanny Kukawka 	eth_hw_addr_random(dev->net);
7811e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n");
782d0cad871SSteve Glendinning }
783d0cad871SSteve Glendinning 
smsc75xx_set_mac_address(struct usbnet * dev)784d0cad871SSteve Glendinning static int smsc75xx_set_mac_address(struct usbnet *dev)
785d0cad871SSteve Glendinning {
786d0cad871SSteve Glendinning 	u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 |
787d0cad871SSteve Glendinning 		dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24;
788d0cad871SSteve Glendinning 	u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
789d0cad871SSteve Glendinning 
790d0cad871SSteve Glendinning 	int ret = smsc75xx_write_reg(dev, RX_ADDRH, addr_hi);
791e3c678e6SSteve Glendinning 	if (ret < 0) {
792e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write RX_ADDRH: %d\n", ret);
793e3c678e6SSteve Glendinning 		return ret;
794e3c678e6SSteve Glendinning 	}
795d0cad871SSteve Glendinning 
796d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, RX_ADDRL, addr_lo);
797e3c678e6SSteve Glendinning 	if (ret < 0) {
798e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write RX_ADDRL: %d\n", ret);
799e3c678e6SSteve Glendinning 		return ret;
800e3c678e6SSteve Glendinning 	}
801d0cad871SSteve Glendinning 
802d0cad871SSteve Glendinning 	addr_hi |= ADDR_FILTX_FB_VALID;
803d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, ADDR_FILTX, addr_hi);
804e3c678e6SSteve Glendinning 	if (ret < 0) {
805e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write ADDR_FILTX: %d\n", ret);
806e3c678e6SSteve Glendinning 		return ret;
807e3c678e6SSteve Glendinning 	}
808d0cad871SSteve Glendinning 
809d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, ADDR_FILTX + 4, addr_lo);
810e3c678e6SSteve Glendinning 	if (ret < 0)
811e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write ADDR_FILTX+4: %d\n", ret);
812d0cad871SSteve Glendinning 
813e3c678e6SSteve Glendinning 	return ret;
814d0cad871SSteve Glendinning }
815d0cad871SSteve Glendinning 
smsc75xx_phy_initialize(struct usbnet * dev)816d0cad871SSteve Glendinning static int smsc75xx_phy_initialize(struct usbnet *dev)
817d0cad871SSteve Glendinning {
818b140504aSSteve Glendinning 	int bmcr, ret, timeout = 0;
819d0cad871SSteve Glendinning 
820d0cad871SSteve Glendinning 	/* Initialize MII structure */
821d0cad871SSteve Glendinning 	dev->mii.dev = dev->net;
822d0cad871SSteve Glendinning 	dev->mii.mdio_read = smsc75xx_mdio_read;
823d0cad871SSteve Glendinning 	dev->mii.mdio_write = smsc75xx_mdio_write;
824d0cad871SSteve Glendinning 	dev->mii.phy_id_mask = 0x1f;
825d0cad871SSteve Glendinning 	dev->mii.reg_num_mask = 0x1f;
826c0b92e4dSSteve Glendinning 	dev->mii.supports_gmii = 1;
827d0cad871SSteve Glendinning 	dev->mii.phy_id = SMSC75XX_INTERNAL_PHY_ID;
828d0cad871SSteve Glendinning 
829d0cad871SSteve Glendinning 	/* reset phy and wait for reset to complete */
830d0cad871SSteve Glendinning 	smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
831d0cad871SSteve Glendinning 
832d0cad871SSteve Glendinning 	do {
833d0cad871SSteve Glendinning 		msleep(10);
834d0cad871SSteve Glendinning 		bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR);
835e3c678e6SSteve Glendinning 		if (bmcr < 0) {
836e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading MII_BMCR\n");
837e3c678e6SSteve Glendinning 			return bmcr;
838e3c678e6SSteve Glendinning 		}
839d0cad871SSteve Glendinning 		timeout++;
8408a1d59d7SSteve Glendinning 	} while ((bmcr & BMCR_RESET) && (timeout < 100));
841d0cad871SSteve Glendinning 
842d0cad871SSteve Glendinning 	if (timeout >= 100) {
8431e1d7412SJoe Perches 		netdev_warn(dev->net, "timeout on PHY Reset\n");
844d0cad871SSteve Glendinning 		return -EIO;
845d0cad871SSteve Glendinning 	}
846d0cad871SSteve Glendinning 
847d461e3daSYuiko Oshino 	/* phy workaround for gig link */
848d461e3daSYuiko Oshino 	smsc75xx_phy_gig_workaround(dev);
849d461e3daSYuiko Oshino 
850d0cad871SSteve Glendinning 	smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
851d0cad871SSteve Glendinning 		ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
852d0cad871SSteve Glendinning 		ADVERTISE_PAUSE_ASYM);
853c0b92e4dSSteve Glendinning 	smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,
854c0b92e4dSSteve Glendinning 		ADVERTISE_1000FULL);
855d0cad871SSteve Glendinning 
856b140504aSSteve Glendinning 	/* read and write to clear phy interrupt status */
857b140504aSSteve Glendinning 	ret = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC);
858e3c678e6SSteve Glendinning 	if (ret < 0) {
859e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
860e3c678e6SSteve Glendinning 		return ret;
861e3c678e6SSteve Glendinning 	}
862e3c678e6SSteve Glendinning 
863b140504aSSteve Glendinning 	smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_SRC, 0xffff);
864d0cad871SSteve Glendinning 
865d0cad871SSteve Glendinning 	smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK,
866d0cad871SSteve Glendinning 		PHY_INT_MASK_DEFAULT);
867d0cad871SSteve Glendinning 	mii_nway_restart(&dev->mii);
868d0cad871SSteve Glendinning 
8691e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n");
870d0cad871SSteve Glendinning 	return 0;
871d0cad871SSteve Glendinning }
872d0cad871SSteve Glendinning 
smsc75xx_set_rx_max_frame_length(struct usbnet * dev,int size)873d0cad871SSteve Glendinning static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size)
874d0cad871SSteve Glendinning {
875d0cad871SSteve Glendinning 	int ret = 0;
876d0cad871SSteve Glendinning 	u32 buf;
877d0cad871SSteve Glendinning 	bool rxenabled;
878d0cad871SSteve Glendinning 
879d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, MAC_RX, &buf);
880e3c678e6SSteve Glendinning 	if (ret < 0) {
881e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret);
882e3c678e6SSteve Glendinning 		return ret;
883e3c678e6SSteve Glendinning 	}
884d0cad871SSteve Glendinning 
885d0cad871SSteve Glendinning 	rxenabled = ((buf & MAC_RX_RXEN) != 0);
886d0cad871SSteve Glendinning 
887d0cad871SSteve Glendinning 	if (rxenabled) {
888d0cad871SSteve Glendinning 		buf &= ~MAC_RX_RXEN;
889d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, MAC_RX, buf);
890e3c678e6SSteve Glendinning 		if (ret < 0) {
891e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
892e3c678e6SSteve Glendinning 			return ret;
893e3c678e6SSteve Glendinning 		}
894d0cad871SSteve Glendinning 	}
895d0cad871SSteve Glendinning 
896d0cad871SSteve Glendinning 	/* add 4 to size for FCS */
897d0cad871SSteve Glendinning 	buf &= ~MAC_RX_MAX_SIZE;
898d0cad871SSteve Glendinning 	buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT) & MAC_RX_MAX_SIZE);
899d0cad871SSteve Glendinning 
900d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, MAC_RX, buf);
901e3c678e6SSteve Glendinning 	if (ret < 0) {
902e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
903e3c678e6SSteve Glendinning 		return ret;
904e3c678e6SSteve Glendinning 	}
905d0cad871SSteve Glendinning 
906d0cad871SSteve Glendinning 	if (rxenabled) {
907d0cad871SSteve Glendinning 		buf |= MAC_RX_RXEN;
908d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, MAC_RX, buf);
909e3c678e6SSteve Glendinning 		if (ret < 0) {
910e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
911e3c678e6SSteve Glendinning 			return ret;
912e3c678e6SSteve Glendinning 		}
913d0cad871SSteve Glendinning 	}
914d0cad871SSteve Glendinning 
915d0cad871SSteve Glendinning 	return 0;
916d0cad871SSteve Glendinning }
917d0cad871SSteve Glendinning 
smsc75xx_change_mtu(struct net_device * netdev,int new_mtu)918d0cad871SSteve Glendinning static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
919d0cad871SSteve Glendinning {
920d0cad871SSteve Glendinning 	struct usbnet *dev = netdev_priv(netdev);
9214c51e536SSteve Glendinning 	int ret;
922d0cad871SSteve Glendinning 
9234c51e536SSteve Glendinning 	ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN);
924e3c678e6SSteve Glendinning 	if (ret < 0) {
925e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to set mac rx frame length\n");
926e3c678e6SSteve Glendinning 		return ret;
927e3c678e6SSteve Glendinning 	}
928d0cad871SSteve Glendinning 
929d0cad871SSteve Glendinning 	return usbnet_change_mtu(netdev, new_mtu);
930d0cad871SSteve Glendinning }
931d0cad871SSteve Glendinning 
93278e47fe4SMichał Mirosław /* Enable or disable Rx checksum offload engine */
smsc75xx_set_features(struct net_device * netdev,netdev_features_t features)933c8f44affSMichał Mirosław static int smsc75xx_set_features(struct net_device *netdev,
934c8f44affSMichał Mirosław 	netdev_features_t features)
93578e47fe4SMichał Mirosław {
93678e47fe4SMichał Mirosław 	struct usbnet *dev = netdev_priv(netdev);
93778e47fe4SMichał Mirosław 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
93878e47fe4SMichał Mirosław 	unsigned long flags;
93978e47fe4SMichał Mirosław 	int ret;
94078e47fe4SMichał Mirosław 
94178e47fe4SMichał Mirosław 	spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
94278e47fe4SMichał Mirosław 
94378e47fe4SMichał Mirosław 	if (features & NETIF_F_RXCSUM)
94478e47fe4SMichał Mirosław 		pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM;
94578e47fe4SMichał Mirosław 	else
94678e47fe4SMichał Mirosław 		pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM);
94778e47fe4SMichał Mirosław 
94878e47fe4SMichał Mirosław 	spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
94978e47fe4SMichał Mirosław 	/* it's racing here! */
95078e47fe4SMichał Mirosław 
95178e47fe4SMichał Mirosław 	ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
95288e80c62SEric Dumazet 	if (ret < 0) {
953e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing RFE_CTL\n");
954e3c678e6SSteve Glendinning 		return ret;
95578e47fe4SMichał Mirosław 	}
95688e80c62SEric Dumazet 	return 0;
95788e80c62SEric Dumazet }
95878e47fe4SMichał Mirosław 
smsc75xx_wait_ready(struct usbnet * dev,int in_pm)95947bbea41SMing Lei static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
9608762cec8SSteve Glendinning {
9618762cec8SSteve Glendinning 	int timeout = 0;
9628762cec8SSteve Glendinning 
9638762cec8SSteve Glendinning 	do {
9648762cec8SSteve Glendinning 		u32 buf;
96547bbea41SMing Lei 		int ret;
96647bbea41SMing Lei 
96747bbea41SMing Lei 		ret = __smsc75xx_read_reg(dev, PMT_CTL, &buf, in_pm);
96847bbea41SMing Lei 
969e3c678e6SSteve Glendinning 		if (ret < 0) {
970e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
971e3c678e6SSteve Glendinning 			return ret;
972e3c678e6SSteve Glendinning 		}
9738762cec8SSteve Glendinning 
9748762cec8SSteve Glendinning 		if (buf & PMT_CTL_DEV_RDY)
9758762cec8SSteve Glendinning 			return 0;
9768762cec8SSteve Glendinning 
9778762cec8SSteve Glendinning 		msleep(10);
9788762cec8SSteve Glendinning 		timeout++;
9798762cec8SSteve Glendinning 	} while (timeout < 100);
9808762cec8SSteve Glendinning 
9811e1d7412SJoe Perches 	netdev_warn(dev->net, "timeout waiting for device ready\n");
9828762cec8SSteve Glendinning 	return -EIO;
9838762cec8SSteve Glendinning }
9848762cec8SSteve Glendinning 
smsc75xx_phy_gig_workaround(struct usbnet * dev)985d461e3daSYuiko Oshino static int smsc75xx_phy_gig_workaround(struct usbnet *dev)
986d461e3daSYuiko Oshino {
987d461e3daSYuiko Oshino 	struct mii_if_info *mii = &dev->mii;
988d461e3daSYuiko Oshino 	int ret = 0, timeout = 0;
989d461e3daSYuiko Oshino 	u32 buf, link_up = 0;
990d461e3daSYuiko Oshino 
991d461e3daSYuiko Oshino 	/* Set the phy in Gig loopback */
992d461e3daSYuiko Oshino 	smsc75xx_mdio_write(dev->net, mii->phy_id, MII_BMCR, 0x4040);
993d461e3daSYuiko Oshino 
994d461e3daSYuiko Oshino 	/* Wait for the link up */
995d461e3daSYuiko Oshino 	do {
996d461e3daSYuiko Oshino 		link_up = smsc75xx_link_ok_nopm(dev);
997d461e3daSYuiko Oshino 		usleep_range(10000, 20000);
998d461e3daSYuiko Oshino 		timeout++;
999d461e3daSYuiko Oshino 	} while ((!link_up) && (timeout < 1000));
1000d461e3daSYuiko Oshino 
1001d461e3daSYuiko Oshino 	if (timeout >= 1000) {
1002d461e3daSYuiko Oshino 		netdev_warn(dev->net, "Timeout waiting for PHY link up\n");
1003d461e3daSYuiko Oshino 		return -EIO;
1004d461e3daSYuiko Oshino 	}
1005d461e3daSYuiko Oshino 
1006d461e3daSYuiko Oshino 	/* phy reset */
1007d461e3daSYuiko Oshino 	ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
1008d461e3daSYuiko Oshino 	if (ret < 0) {
1009d461e3daSYuiko Oshino 		netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
1010d461e3daSYuiko Oshino 		return ret;
1011d461e3daSYuiko Oshino 	}
1012d461e3daSYuiko Oshino 
1013d461e3daSYuiko Oshino 	buf |= PMT_CTL_PHY_RST;
1014d461e3daSYuiko Oshino 
1015d461e3daSYuiko Oshino 	ret = smsc75xx_write_reg(dev, PMT_CTL, buf);
1016d461e3daSYuiko Oshino 	if (ret < 0) {
1017d461e3daSYuiko Oshino 		netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret);
1018d461e3daSYuiko Oshino 		return ret;
1019d461e3daSYuiko Oshino 	}
1020d461e3daSYuiko Oshino 
1021d461e3daSYuiko Oshino 	timeout = 0;
1022d461e3daSYuiko Oshino 	do {
1023d461e3daSYuiko Oshino 		usleep_range(10000, 20000);
1024d461e3daSYuiko Oshino 		ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
1025d461e3daSYuiko Oshino 		if (ret < 0) {
1026d461e3daSYuiko Oshino 			netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n",
1027d461e3daSYuiko Oshino 				    ret);
1028d461e3daSYuiko Oshino 			return ret;
1029d461e3daSYuiko Oshino 		}
1030d461e3daSYuiko Oshino 		timeout++;
1031d461e3daSYuiko Oshino 	} while ((buf & PMT_CTL_PHY_RST) && (timeout < 100));
1032d461e3daSYuiko Oshino 
1033d461e3daSYuiko Oshino 	if (timeout >= 100) {
1034d461e3daSYuiko Oshino 		netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
1035d461e3daSYuiko Oshino 		return -EIO;
1036d461e3daSYuiko Oshino 	}
1037d461e3daSYuiko Oshino 
1038d461e3daSYuiko Oshino 	return 0;
1039d461e3daSYuiko Oshino }
1040d461e3daSYuiko Oshino 
smsc75xx_reset(struct usbnet * dev)1041d0cad871SSteve Glendinning static int smsc75xx_reset(struct usbnet *dev)
1042d0cad871SSteve Glendinning {
1043d0cad871SSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
1044d0cad871SSteve Glendinning 	u32 buf;
1045d0cad871SSteve Glendinning 	int ret = 0, timeout;
1046d0cad871SSteve Glendinning 
10471e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset\n");
1048d0cad871SSteve Glendinning 
104947bbea41SMing Lei 	ret = smsc75xx_wait_ready(dev, 0);
1050e3c678e6SSteve Glendinning 	if (ret < 0) {
1051e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "device not ready in smsc75xx_reset\n");
1052e3c678e6SSteve Glendinning 		return ret;
1053e3c678e6SSteve Glendinning 	}
10548762cec8SSteve Glendinning 
1055d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
1056e3c678e6SSteve Glendinning 	if (ret < 0) {
1057e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
1058e3c678e6SSteve Glendinning 		return ret;
1059e3c678e6SSteve Glendinning 	}
1060d0cad871SSteve Glendinning 
1061d0cad871SSteve Glendinning 	buf |= HW_CFG_LRST;
1062d0cad871SSteve Glendinning 
1063d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, HW_CFG, buf);
1064e3c678e6SSteve Glendinning 	if (ret < 0) {
1065e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
1066e3c678e6SSteve Glendinning 		return ret;
1067e3c678e6SSteve Glendinning 	}
1068d0cad871SSteve Glendinning 
1069d0cad871SSteve Glendinning 	timeout = 0;
1070d0cad871SSteve Glendinning 	do {
1071d0cad871SSteve Glendinning 		msleep(10);
1072d0cad871SSteve Glendinning 		ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
1073e3c678e6SSteve Glendinning 		if (ret < 0) {
1074e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
1075e3c678e6SSteve Glendinning 			return ret;
1076e3c678e6SSteve Glendinning 		}
1077d0cad871SSteve Glendinning 		timeout++;
1078d0cad871SSteve Glendinning 	} while ((buf & HW_CFG_LRST) && (timeout < 100));
1079d0cad871SSteve Glendinning 
1080d0cad871SSteve Glendinning 	if (timeout >= 100) {
10811e1d7412SJoe Perches 		netdev_warn(dev->net, "timeout on completion of Lite Reset\n");
1082d0cad871SSteve Glendinning 		return -EIO;
1083d0cad871SSteve Glendinning 	}
1084d0cad871SSteve Glendinning 
10851e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "Lite reset complete, resetting PHY\n");
1086d0cad871SSteve Glendinning 
1087d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
1088e3c678e6SSteve Glendinning 	if (ret < 0) {
1089e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
1090e3c678e6SSteve Glendinning 		return ret;
1091e3c678e6SSteve Glendinning 	}
1092d0cad871SSteve Glendinning 
1093d0cad871SSteve Glendinning 	buf |= PMT_CTL_PHY_RST;
1094d0cad871SSteve Glendinning 
1095d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, PMT_CTL, buf);
1096e3c678e6SSteve Glendinning 	if (ret < 0) {
1097e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret);
1098e3c678e6SSteve Glendinning 		return ret;
1099e3c678e6SSteve Glendinning 	}
1100d0cad871SSteve Glendinning 
1101d0cad871SSteve Glendinning 	timeout = 0;
1102d0cad871SSteve Glendinning 	do {
1103d0cad871SSteve Glendinning 		msleep(10);
1104d0cad871SSteve Glendinning 		ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
1105e3c678e6SSteve Glendinning 		if (ret < 0) {
1106e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
1107e3c678e6SSteve Glendinning 			return ret;
1108e3c678e6SSteve Glendinning 		}
1109d0cad871SSteve Glendinning 		timeout++;
1110d0cad871SSteve Glendinning 	} while ((buf & PMT_CTL_PHY_RST) && (timeout < 100));
1111d0cad871SSteve Glendinning 
1112d0cad871SSteve Glendinning 	if (timeout >= 100) {
11131e1d7412SJoe Perches 		netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
1114d0cad871SSteve Glendinning 		return -EIO;
1115d0cad871SSteve Glendinning 	}
1116d0cad871SSteve Glendinning 
11171e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "PHY reset complete\n");
1118d0cad871SSteve Glendinning 
1119d0cad871SSteve Glendinning 	ret = smsc75xx_set_mac_address(dev);
1120e3c678e6SSteve Glendinning 	if (ret < 0) {
1121e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to set mac address\n");
1122e3c678e6SSteve Glendinning 		return ret;
1123e3c678e6SSteve Glendinning 	}
1124d0cad871SSteve Glendinning 
11251e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "MAC Address: %pM\n",
11261e1d7412SJoe Perches 		  dev->net->dev_addr);
1127d0cad871SSteve Glendinning 
1128d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
1129e3c678e6SSteve Glendinning 	if (ret < 0) {
1130e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
1131e3c678e6SSteve Glendinning 		return ret;
1132e3c678e6SSteve Glendinning 	}
1133d0cad871SSteve Glendinning 
11341e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x\n",
11351e1d7412SJoe Perches 		  buf);
1136d0cad871SSteve Glendinning 
1137d0cad871SSteve Glendinning 	buf |= HW_CFG_BIR;
1138d0cad871SSteve Glendinning 
1139d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, HW_CFG, buf);
1140e3c678e6SSteve Glendinning 	if (ret < 0) {
1141e3c678e6SSteve Glendinning 		netdev_warn(dev->net,  "Failed to write HW_CFG: %d\n", ret);
1142e3c678e6SSteve Glendinning 		return ret;
1143e3c678e6SSteve Glendinning 	}
1144d0cad871SSteve Glendinning 
1145d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
1146e3c678e6SSteve Glendinning 	if (ret < 0) {
1147e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
1148e3c678e6SSteve Glendinning 		return ret;
1149e3c678e6SSteve Glendinning 	}
1150d0cad871SSteve Glendinning 
11511e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG after writing HW_CFG_BIR: 0x%08x\n",
11521e1d7412SJoe Perches 		  buf);
1153d0cad871SSteve Glendinning 
1154d0cad871SSteve Glendinning 	if (!turbo_mode) {
1155d0cad871SSteve Glendinning 		buf = 0;
1156d0cad871SSteve Glendinning 		dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
1157d0cad871SSteve Glendinning 	} else if (dev->udev->speed == USB_SPEED_HIGH) {
1158d0cad871SSteve Glendinning 		buf = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
1159d0cad871SSteve Glendinning 		dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
1160d0cad871SSteve Glendinning 	} else {
1161d0cad871SSteve Glendinning 		buf = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
1162d0cad871SSteve Glendinning 		dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
1163d0cad871SSteve Glendinning 	}
1164d0cad871SSteve Glendinning 
11651e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n",
1166d0cad871SSteve Glendinning 		  (ulong)dev->rx_urb_size);
1167d0cad871SSteve Glendinning 
1168d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, BURST_CAP, buf);
1169e3c678e6SSteve Glendinning 	if (ret < 0) {
1170e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret);
1171e3c678e6SSteve Glendinning 		return ret;
1172e3c678e6SSteve Glendinning 	}
1173d0cad871SSteve Glendinning 
1174d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, BURST_CAP, &buf);
1175e3c678e6SSteve Glendinning 	if (ret < 0) {
1176e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret);
1177e3c678e6SSteve Glendinning 		return ret;
1178e3c678e6SSteve Glendinning 	}
1179d0cad871SSteve Glendinning 
1180d0cad871SSteve Glendinning 	netif_dbg(dev, ifup, dev->net,
11811e1d7412SJoe Perches 		  "Read Value from BURST_CAP after writing: 0x%08x\n", buf);
1182d0cad871SSteve Glendinning 
1183d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
1184e3c678e6SSteve Glendinning 	if (ret < 0) {
1185e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write BULK_IN_DLY: %d\n", ret);
1186e3c678e6SSteve Glendinning 		return ret;
1187e3c678e6SSteve Glendinning 	}
1188d0cad871SSteve Glendinning 
1189d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, BULK_IN_DLY, &buf);
1190e3c678e6SSteve Glendinning 	if (ret < 0) {
1191e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret);
1192e3c678e6SSteve Glendinning 		return ret;
1193e3c678e6SSteve Glendinning 	}
1194d0cad871SSteve Glendinning 
1195d0cad871SSteve Glendinning 	netif_dbg(dev, ifup, dev->net,
11961e1d7412SJoe Perches 		  "Read Value from BULK_IN_DLY after writing: 0x%08x\n", buf);
1197d0cad871SSteve Glendinning 
1198d0cad871SSteve Glendinning 	if (turbo_mode) {
1199d0cad871SSteve Glendinning 		ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
1200e3c678e6SSteve Glendinning 		if (ret < 0) {
1201e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
1202e3c678e6SSteve Glendinning 			return ret;
1203e3c678e6SSteve Glendinning 		}
1204d0cad871SSteve Glendinning 
12051e1d7412SJoe Perches 		netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x\n", buf);
1206d0cad871SSteve Glendinning 
1207d0cad871SSteve Glendinning 		buf |= (HW_CFG_MEF | HW_CFG_BCE);
1208d0cad871SSteve Glendinning 
1209d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, HW_CFG, buf);
1210e3c678e6SSteve Glendinning 		if (ret < 0) {
1211e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
1212e3c678e6SSteve Glendinning 			return ret;
1213e3c678e6SSteve Glendinning 		}
1214d0cad871SSteve Glendinning 
1215d0cad871SSteve Glendinning 		ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
1216e3c678e6SSteve Glendinning 		if (ret < 0) {
1217e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
1218e3c678e6SSteve Glendinning 			return ret;
1219e3c678e6SSteve Glendinning 		}
1220d0cad871SSteve Glendinning 
12211e1d7412SJoe Perches 		netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x\n", buf);
1222d0cad871SSteve Glendinning 	}
1223d0cad871SSteve Glendinning 
1224d0cad871SSteve Glendinning 	/* set FIFO sizes */
1225d0cad871SSteve Glendinning 	buf = (MAX_RX_FIFO_SIZE - 512) / 512;
1226d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, FCT_RX_FIFO_END, buf);
1227e3c678e6SSteve Glendinning 	if (ret < 0) {
1228e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write FCT_RX_FIFO_END: %d\n", ret);
1229e3c678e6SSteve Glendinning 		return ret;
1230e3c678e6SSteve Glendinning 	}
1231d0cad871SSteve Glendinning 
12321e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "FCT_RX_FIFO_END set to 0x%08x\n", buf);
1233d0cad871SSteve Glendinning 
1234d0cad871SSteve Glendinning 	buf = (MAX_TX_FIFO_SIZE - 512) / 512;
1235d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, FCT_TX_FIFO_END, buf);
1236e3c678e6SSteve Glendinning 	if (ret < 0) {
1237e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write FCT_TX_FIFO_END: %d\n", ret);
1238e3c678e6SSteve Glendinning 		return ret;
1239e3c678e6SSteve Glendinning 	}
1240d0cad871SSteve Glendinning 
12411e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "FCT_TX_FIFO_END set to 0x%08x\n", buf);
1242d0cad871SSteve Glendinning 
1243d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL);
1244e3c678e6SSteve Glendinning 	if (ret < 0) {
1245e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write INT_STS: %d\n", ret);
1246e3c678e6SSteve Glendinning 		return ret;
1247e3c678e6SSteve Glendinning 	}
1248d0cad871SSteve Glendinning 
1249d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, ID_REV, &buf);
1250e3c678e6SSteve Glendinning 	if (ret < 0) {
1251e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
1252e3c678e6SSteve Glendinning 		return ret;
1253e3c678e6SSteve Glendinning 	}
1254d0cad871SSteve Glendinning 
12551e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", buf);
1256d0cad871SSteve Glendinning 
125797138a1cSSteve Glendinning 	ret = smsc75xx_read_reg(dev, E2P_CMD, &buf);
1258e3c678e6SSteve Glendinning 	if (ret < 0) {
1259e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read E2P_CMD: %d\n", ret);
1260e3c678e6SSteve Glendinning 		return ret;
1261e3c678e6SSteve Glendinning 	}
126297138a1cSSteve Glendinning 
126397138a1cSSteve Glendinning 	/* only set default GPIO/LED settings if no EEPROM is detected */
126497138a1cSSteve Glendinning 	if (!(buf & E2P_CMD_LOADED)) {
1265d0cad871SSteve Glendinning 		ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf);
1266e3c678e6SSteve Glendinning 		if (ret < 0) {
1267e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to read LED_GPIO_CFG: %d\n", ret);
1268e3c678e6SSteve Glendinning 			return ret;
1269e3c678e6SSteve Glendinning 		}
1270d0cad871SSteve Glendinning 
1271d0cad871SSteve Glendinning 		buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL);
1272d0cad871SSteve Glendinning 		buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL;
1273d0cad871SSteve Glendinning 
1274d0cad871SSteve Glendinning 		ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf);
1275e3c678e6SSteve Glendinning 		if (ret < 0) {
1276e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Failed to write LED_GPIO_CFG: %d\n", ret);
1277e3c678e6SSteve Glendinning 			return ret;
1278e3c678e6SSteve Glendinning 		}
127997138a1cSSteve Glendinning 	}
1280d0cad871SSteve Glendinning 
1281d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, FLOW, 0);
1282e3c678e6SSteve Glendinning 	if (ret < 0) {
1283e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
1284e3c678e6SSteve Glendinning 		return ret;
1285e3c678e6SSteve Glendinning 	}
1286d0cad871SSteve Glendinning 
1287d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, FCT_FLOW, 0);
1288e3c678e6SSteve Glendinning 	if (ret < 0) {
1289e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write FCT_FLOW: %d\n", ret);
1290e3c678e6SSteve Glendinning 		return ret;
1291e3c678e6SSteve Glendinning 	}
1292d0cad871SSteve Glendinning 
1293d0cad871SSteve Glendinning 	/* Don't need rfe_ctl_lock during initialisation */
1294d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl);
1295e3c678e6SSteve Glendinning 	if (ret < 0) {
1296e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read RFE_CTL: %d\n", ret);
1297e3c678e6SSteve Glendinning 		return ret;
1298e3c678e6SSteve Glendinning 	}
1299d0cad871SSteve Glendinning 
1300d0cad871SSteve Glendinning 	pdata->rfe_ctl |= RFE_CTL_AB | RFE_CTL_DPF;
1301d0cad871SSteve Glendinning 
1302d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
1303e3c678e6SSteve Glendinning 	if (ret < 0) {
1304e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write RFE_CTL: %d\n", ret);
1305e3c678e6SSteve Glendinning 		return ret;
1306e3c678e6SSteve Glendinning 	}
1307d0cad871SSteve Glendinning 
1308d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl);
1309e3c678e6SSteve Glendinning 	if (ret < 0) {
1310e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read RFE_CTL: %d\n", ret);
1311e3c678e6SSteve Glendinning 		return ret;
1312e3c678e6SSteve Glendinning 	}
1313d0cad871SSteve Glendinning 
13141e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x\n",
13151e1d7412SJoe Perches 		  pdata->rfe_ctl);
1316d0cad871SSteve Glendinning 
1317d0cad871SSteve Glendinning 	/* Enable or disable checksum offload engines */
131878e47fe4SMichał Mirosław 	smsc75xx_set_features(dev->net, dev->net->features);
1319d0cad871SSteve Glendinning 
1320d0cad871SSteve Glendinning 	smsc75xx_set_multicast(dev->net);
1321d0cad871SSteve Glendinning 
1322d0cad871SSteve Glendinning 	ret = smsc75xx_phy_initialize(dev);
1323e3c678e6SSteve Glendinning 	if (ret < 0) {
1324e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to initialize PHY: %d\n", ret);
1325e3c678e6SSteve Glendinning 		return ret;
1326e3c678e6SSteve Glendinning 	}
1327d0cad871SSteve Glendinning 
1328d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, INT_EP_CTL, &buf);
1329e3c678e6SSteve Glendinning 	if (ret < 0) {
1330e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret);
1331e3c678e6SSteve Glendinning 		return ret;
1332e3c678e6SSteve Glendinning 	}
1333d0cad871SSteve Glendinning 
1334d0cad871SSteve Glendinning 	/* enable PHY interrupts */
1335d0cad871SSteve Glendinning 	buf |= INT_ENP_PHY_INT;
1336d0cad871SSteve Glendinning 
1337d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf);
1338e3c678e6SSteve Glendinning 	if (ret < 0) {
1339e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret);
1340e3c678e6SSteve Glendinning 		return ret;
1341e3c678e6SSteve Glendinning 	}
1342d0cad871SSteve Glendinning 
13432f3a081eSSteve Glendinning 	/* allow mac to detect speed and duplex from phy */
13442f3a081eSSteve Glendinning 	ret = smsc75xx_read_reg(dev, MAC_CR, &buf);
1345e3c678e6SSteve Glendinning 	if (ret < 0) {
1346e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret);
1347e3c678e6SSteve Glendinning 		return ret;
1348e3c678e6SSteve Glendinning 	}
13492f3a081eSSteve Glendinning 
13502f3a081eSSteve Glendinning 	buf |= (MAC_CR_ADD | MAC_CR_ASD);
13512f3a081eSSteve Glendinning 	ret = smsc75xx_write_reg(dev, MAC_CR, buf);
1352e3c678e6SSteve Glendinning 	if (ret < 0) {
1353e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret);
1354e3c678e6SSteve Glendinning 		return ret;
1355e3c678e6SSteve Glendinning 	}
13562f3a081eSSteve Glendinning 
1357d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, MAC_TX, &buf);
1358e3c678e6SSteve Glendinning 	if (ret < 0) {
1359e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read MAC_TX: %d\n", ret);
1360e3c678e6SSteve Glendinning 		return ret;
1361e3c678e6SSteve Glendinning 	}
1362d0cad871SSteve Glendinning 
1363d0cad871SSteve Glendinning 	buf |= MAC_TX_TXEN;
1364d0cad871SSteve Glendinning 
1365d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, MAC_TX, buf);
1366e3c678e6SSteve Glendinning 	if (ret < 0) {
1367e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write MAC_TX: %d\n", ret);
1368e3c678e6SSteve Glendinning 		return ret;
1369e3c678e6SSteve Glendinning 	}
1370d0cad871SSteve Glendinning 
13711e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "MAC_TX set to 0x%08x\n", buf);
1372d0cad871SSteve Glendinning 
1373d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, FCT_TX_CTL, &buf);
1374e3c678e6SSteve Glendinning 	if (ret < 0) {
1375e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read FCT_TX_CTL: %d\n", ret);
1376e3c678e6SSteve Glendinning 		return ret;
1377e3c678e6SSteve Glendinning 	}
1378d0cad871SSteve Glendinning 
1379d0cad871SSteve Glendinning 	buf |= FCT_TX_CTL_EN;
1380d0cad871SSteve Glendinning 
1381d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, FCT_TX_CTL, buf);
1382e3c678e6SSteve Glendinning 	if (ret < 0) {
1383e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write FCT_TX_CTL: %d\n", ret);
1384e3c678e6SSteve Glendinning 		return ret;
1385e3c678e6SSteve Glendinning 	}
1386d0cad871SSteve Glendinning 
13871e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x\n", buf);
1388d0cad871SSteve Glendinning 
13894c51e536SSteve Glendinning 	ret = smsc75xx_set_rx_max_frame_length(dev, dev->net->mtu + ETH_HLEN);
1390e3c678e6SSteve Glendinning 	if (ret < 0) {
1391e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to set max rx frame length\n");
1392e3c678e6SSteve Glendinning 		return ret;
1393e3c678e6SSteve Glendinning 	}
1394d0cad871SSteve Glendinning 
1395d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, MAC_RX, &buf);
1396e3c678e6SSteve Glendinning 	if (ret < 0) {
1397e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret);
1398e3c678e6SSteve Glendinning 		return ret;
1399e3c678e6SSteve Glendinning 	}
1400d0cad871SSteve Glendinning 
1401d0cad871SSteve Glendinning 	buf |= MAC_RX_RXEN;
1402d0cad871SSteve Glendinning 
1403d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, MAC_RX, buf);
1404e3c678e6SSteve Glendinning 	if (ret < 0) {
1405e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
1406e3c678e6SSteve Glendinning 		return ret;
1407e3c678e6SSteve Glendinning 	}
1408d0cad871SSteve Glendinning 
14091e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "MAC_RX set to 0x%08x\n", buf);
1410d0cad871SSteve Glendinning 
1411d0cad871SSteve Glendinning 	ret = smsc75xx_read_reg(dev, FCT_RX_CTL, &buf);
1412e3c678e6SSteve Glendinning 	if (ret < 0) {
1413e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read FCT_RX_CTL: %d\n", ret);
1414e3c678e6SSteve Glendinning 		return ret;
1415e3c678e6SSteve Glendinning 	}
1416d0cad871SSteve Glendinning 
1417d0cad871SSteve Glendinning 	buf |= FCT_RX_CTL_EN;
1418d0cad871SSteve Glendinning 
1419d0cad871SSteve Glendinning 	ret = smsc75xx_write_reg(dev, FCT_RX_CTL, buf);
1420e3c678e6SSteve Glendinning 	if (ret < 0) {
1421e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write FCT_RX_CTL: %d\n", ret);
1422e3c678e6SSteve Glendinning 		return ret;
1423e3c678e6SSteve Glendinning 	}
1424d0cad871SSteve Glendinning 
14251e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "FCT_RX_CTL set to 0x%08x\n", buf);
1426d0cad871SSteve Glendinning 
14271e1d7412SJoe Perches 	netif_dbg(dev, ifup, dev->net, "smsc75xx_reset, return 0\n");
1428d0cad871SSteve Glendinning 	return 0;
1429d0cad871SSteve Glendinning }
1430d0cad871SSteve Glendinning 
1431d0cad871SSteve Glendinning static const struct net_device_ops smsc75xx_netdev_ops = {
1432d0cad871SSteve Glendinning 	.ndo_open		= usbnet_open,
1433d0cad871SSteve Glendinning 	.ndo_stop		= usbnet_stop,
1434d0cad871SSteve Glendinning 	.ndo_start_xmit		= usbnet_start_xmit,
1435d0cad871SSteve Glendinning 	.ndo_tx_timeout		= usbnet_tx_timeout,
1436323955a0SHeiner Kallweit 	.ndo_get_stats64	= dev_get_tstats64,
1437d0cad871SSteve Glendinning 	.ndo_change_mtu		= smsc75xx_change_mtu,
1438d0cad871SSteve Glendinning 	.ndo_set_mac_address 	= eth_mac_addr,
1439d0cad871SSteve Glendinning 	.ndo_validate_addr	= eth_validate_addr,
1440a7605370SArnd Bergmann 	.ndo_eth_ioctl		= smsc75xx_ioctl,
1441afc4b13dSJiri Pirko 	.ndo_set_rx_mode	= smsc75xx_set_multicast,
144278e47fe4SMichał Mirosław 	.ndo_set_features	= smsc75xx_set_features,
1443d0cad871SSteve Glendinning };
1444d0cad871SSteve Glendinning 
smsc75xx_bind(struct usbnet * dev,struct usb_interface * intf)1445d0cad871SSteve Glendinning static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
1446d0cad871SSteve Glendinning {
1447d0cad871SSteve Glendinning 	struct smsc75xx_priv *pdata = NULL;
1448d0cad871SSteve Glendinning 	int ret;
1449d0cad871SSteve Glendinning 
1450d0cad871SSteve Glendinning 	printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
1451d0cad871SSteve Glendinning 
1452d0cad871SSteve Glendinning 	ret = usbnet_get_endpoints(dev, intf);
1453e3c678e6SSteve Glendinning 	if (ret < 0) {
1454e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret);
1455e3c678e6SSteve Glendinning 		return ret;
1456e3c678e6SSteve Glendinning 	}
1457d0cad871SSteve Glendinning 
1458d0cad871SSteve Glendinning 	dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv),
1459d0cad871SSteve Glendinning 					      GFP_KERNEL);
1460d0cad871SSteve Glendinning 
1461d0cad871SSteve Glendinning 	pdata = (struct smsc75xx_priv *)(dev->data[0]);
146238673c82SJoe Perches 	if (!pdata)
1463d0cad871SSteve Glendinning 		return -ENOMEM;
1464d0cad871SSteve Glendinning 
1465d0cad871SSteve Glendinning 	pdata->dev = dev;
1466d0cad871SSteve Glendinning 
1467d0cad871SSteve Glendinning 	spin_lock_init(&pdata->rfe_ctl_lock);
1468d0cad871SSteve Glendinning 	mutex_init(&pdata->dataport_mutex);
1469d0cad871SSteve Glendinning 
1470d0cad871SSteve Glendinning 	INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);
1471d0cad871SSteve Glendinning 
147220f01703SEric Dumazet 	if (DEFAULT_TX_CSUM_ENABLE)
147378e47fe4SMichał Mirosław 		dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
147420f01703SEric Dumazet 
147578e47fe4SMichał Mirosław 	if (DEFAULT_RX_CSUM_ENABLE)
147678e47fe4SMichał Mirosław 		dev->net->features |= NETIF_F_RXCSUM;
1477d0cad871SSteve Glendinning 
147878e47fe4SMichał Mirosław 	dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
147920f01703SEric Dumazet 				NETIF_F_RXCSUM;
1480d0cad871SSteve Glendinning 
1481481705a1SSteve Glendinning 	ret = smsc75xx_wait_ready(dev, 0);
1482481705a1SSteve Glendinning 	if (ret < 0) {
1483481705a1SSteve Glendinning 		netdev_warn(dev->net, "device not ready in smsc75xx_bind\n");
148456b786d8SDongliang Mu 		goto free_pdata;
1485481705a1SSteve Glendinning 	}
1486481705a1SSteve Glendinning 
1487481705a1SSteve Glendinning 	smsc75xx_init_mac_address(dev);
1488481705a1SSteve Glendinning 
1489d0cad871SSteve Glendinning 	/* Init all registers */
1490d0cad871SSteve Glendinning 	ret = smsc75xx_reset(dev);
1491e3c678e6SSteve Glendinning 	if (ret < 0) {
1492e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "smsc75xx_reset error %d\n", ret);
149356b786d8SDongliang Mu 		goto cancel_work;
1494e3c678e6SSteve Glendinning 	}
1495d0cad871SSteve Glendinning 
1496d0cad871SSteve Glendinning 	dev->net->netdev_ops = &smsc75xx_netdev_ops;
1497d0cad871SSteve Glendinning 	dev->net->ethtool_ops = &smsc75xx_ethtool_ops;
1498d0cad871SSteve Glendinning 	dev->net->flags |= IFF_MULTICAST;
1499d0cad871SSteve Glendinning 	dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD;
1500a99ff7d0SStephane Fillod 	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
1501f77f0aeeSJarod Wilson 	dev->net->max_mtu = MAX_SINGLE_PACKET_SIZE;
1502d0cad871SSteve Glendinning 	return 0;
150346a8b29cSPavel Skripkin 
150456b786d8SDongliang Mu cancel_work:
150556b786d8SDongliang Mu 	cancel_work_sync(&pdata->set_multicast);
150656b786d8SDongliang Mu free_pdata:
150746a8b29cSPavel Skripkin 	kfree(pdata);
150856b786d8SDongliang Mu 	dev->data[0] = 0;
150946a8b29cSPavel Skripkin 	return ret;
1510d0cad871SSteve Glendinning }
1511d0cad871SSteve Glendinning 
smsc75xx_unbind(struct usbnet * dev,struct usb_interface * intf)1512d0cad871SSteve Glendinning static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
1513d0cad871SSteve Glendinning {
1514d0cad871SSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
1515d0cad871SSteve Glendinning 	if (pdata) {
1516f7b2a56eSYu Zhao 		cancel_work_sync(&pdata->set_multicast);
15171e1d7412SJoe Perches 		netif_dbg(dev, ifdown, dev->net, "free pdata\n");
1518d0cad871SSteve Glendinning 		kfree(pdata);
1519d0cad871SSteve Glendinning 		dev->data[0] = 0;
1520d0cad871SSteve Glendinning 	}
1521d0cad871SSteve Glendinning }
1522d0cad871SSteve Glendinning 
smsc_crc(const u8 * buffer,size_t len)1523899a391bSSteve Glendinning static u16 smsc_crc(const u8 *buffer, size_t len)
1524899a391bSSteve Glendinning {
1525899a391bSSteve Glendinning 	return bitrev16(crc16(0xFFFF, buffer, len));
1526899a391bSSteve Glendinning }
1527899a391bSSteve Glendinning 
smsc75xx_write_wuff(struct usbnet * dev,int filter,u32 wuf_cfg,u32 wuf_mask1)1528899a391bSSteve Glendinning static int smsc75xx_write_wuff(struct usbnet *dev, int filter, u32 wuf_cfg,
1529899a391bSSteve Glendinning 			       u32 wuf_mask1)
1530899a391bSSteve Glendinning {
1531899a391bSSteve Glendinning 	int cfg_base = WUF_CFGX + filter * 4;
1532899a391bSSteve Glendinning 	int mask_base = WUF_MASKX + filter * 16;
1533899a391bSSteve Glendinning 	int ret;
1534899a391bSSteve Glendinning 
1535899a391bSSteve Glendinning 	ret = smsc75xx_write_reg(dev, cfg_base, wuf_cfg);
1536e3c678e6SSteve Glendinning 	if (ret < 0) {
1537e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing WUF_CFGX\n");
1538e3c678e6SSteve Glendinning 		return ret;
1539e3c678e6SSteve Glendinning 	}
1540899a391bSSteve Glendinning 
1541899a391bSSteve Glendinning 	ret = smsc75xx_write_reg(dev, mask_base, wuf_mask1);
1542e3c678e6SSteve Glendinning 	if (ret < 0) {
1543e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing WUF_MASKX\n");
1544e3c678e6SSteve Glendinning 		return ret;
1545e3c678e6SSteve Glendinning 	}
1546899a391bSSteve Glendinning 
1547899a391bSSteve Glendinning 	ret = smsc75xx_write_reg(dev, mask_base + 4, 0);
1548e3c678e6SSteve Glendinning 	if (ret < 0) {
1549e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing WUF_MASKX\n");
1550e3c678e6SSteve Glendinning 		return ret;
1551e3c678e6SSteve Glendinning 	}
1552899a391bSSteve Glendinning 
1553899a391bSSteve Glendinning 	ret = smsc75xx_write_reg(dev, mask_base + 8, 0);
1554e3c678e6SSteve Glendinning 	if (ret < 0) {
1555e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing WUF_MASKX\n");
1556e3c678e6SSteve Glendinning 		return ret;
1557e3c678e6SSteve Glendinning 	}
1558899a391bSSteve Glendinning 
1559899a391bSSteve Glendinning 	ret = smsc75xx_write_reg(dev, mask_base + 12, 0);
1560e3c678e6SSteve Glendinning 	if (ret < 0) {
1561e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing WUF_MASKX\n");
1562e3c678e6SSteve Glendinning 		return ret;
1563e3c678e6SSteve Glendinning 	}
1564899a391bSSteve Glendinning 
1565899a391bSSteve Glendinning 	return 0;
1566899a391bSSteve Glendinning }
1567899a391bSSteve Glendinning 
smsc75xx_enter_suspend0(struct usbnet * dev)15689deb2757SSteve Glendinning static int smsc75xx_enter_suspend0(struct usbnet *dev)
15699deb2757SSteve Glendinning {
1570b4cdea9cSSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
15719deb2757SSteve Glendinning 	u32 val;
15729deb2757SSteve Glendinning 	int ret;
15739deb2757SSteve Glendinning 
15749deb2757SSteve Glendinning 	ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
1575e3c678e6SSteve Glendinning 	if (ret < 0) {
1576e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading PMT_CTL\n");
1577e3c678e6SSteve Glendinning 		return ret;
1578e3c678e6SSteve Glendinning 	}
15799deb2757SSteve Glendinning 
15809deb2757SSteve Glendinning 	val &= (~(PMT_CTL_SUS_MODE | PMT_CTL_PHY_RST));
15819deb2757SSteve Glendinning 	val |= PMT_CTL_SUS_MODE_0 | PMT_CTL_WOL_EN | PMT_CTL_WUPS;
15829deb2757SSteve Glendinning 
15839deb2757SSteve Glendinning 	ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1584e3c678e6SSteve Glendinning 	if (ret < 0) {
1585e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing PMT_CTL\n");
1586e3c678e6SSteve Glendinning 		return ret;
1587e3c678e6SSteve Glendinning 	}
15889deb2757SSteve Glendinning 
1589351f33d9SSteve Glendinning 	pdata->suspend_flags |= SUSPEND_SUSPEND0;
1590b4cdea9cSSteve Glendinning 
15919deb2757SSteve Glendinning 	return 0;
15929deb2757SSteve Glendinning }
15939deb2757SSteve Glendinning 
smsc75xx_enter_suspend1(struct usbnet * dev)1594f329ccdcSSteve Glendinning static int smsc75xx_enter_suspend1(struct usbnet *dev)
1595f329ccdcSSteve Glendinning {
1596b4cdea9cSSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
1597f329ccdcSSteve Glendinning 	u32 val;
1598f329ccdcSSteve Glendinning 	int ret;
1599f329ccdcSSteve Glendinning 
1600f329ccdcSSteve Glendinning 	ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
1601e3c678e6SSteve Glendinning 	if (ret < 0) {
1602e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading PMT_CTL\n");
1603e3c678e6SSteve Glendinning 		return ret;
1604e3c678e6SSteve Glendinning 	}
1605f329ccdcSSteve Glendinning 
1606f329ccdcSSteve Glendinning 	val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
1607f329ccdcSSteve Glendinning 	val |= PMT_CTL_SUS_MODE_1;
1608f329ccdcSSteve Glendinning 
1609f329ccdcSSteve Glendinning 	ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1610e3c678e6SSteve Glendinning 	if (ret < 0) {
1611e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing PMT_CTL\n");
1612e3c678e6SSteve Glendinning 		return ret;
1613e3c678e6SSteve Glendinning 	}
1614f329ccdcSSteve Glendinning 
1615f329ccdcSSteve Glendinning 	/* clear wol status, enable energy detection */
1616f329ccdcSSteve Glendinning 	val &= ~PMT_CTL_WUPS;
1617f329ccdcSSteve Glendinning 	val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN);
1618f329ccdcSSteve Glendinning 
1619f329ccdcSSteve Glendinning 	ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1620e3c678e6SSteve Glendinning 	if (ret < 0) {
1621e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing PMT_CTL\n");
1622e3c678e6SSteve Glendinning 		return ret;
1623e3c678e6SSteve Glendinning 	}
1624f329ccdcSSteve Glendinning 
1625351f33d9SSteve Glendinning 	pdata->suspend_flags |= SUSPEND_SUSPEND1;
1626b4cdea9cSSteve Glendinning 
1627f329ccdcSSteve Glendinning 	return 0;
1628f329ccdcSSteve Glendinning }
1629f329ccdcSSteve Glendinning 
smsc75xx_enter_suspend2(struct usbnet * dev)16309deb2757SSteve Glendinning static int smsc75xx_enter_suspend2(struct usbnet *dev)
16319deb2757SSteve Glendinning {
1632b4cdea9cSSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
16339deb2757SSteve Glendinning 	u32 val;
16349deb2757SSteve Glendinning 	int ret;
16359deb2757SSteve Glendinning 
16369deb2757SSteve Glendinning 	ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
1637e3c678e6SSteve Glendinning 	if (ret < 0) {
1638e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading PMT_CTL\n");
1639e3c678e6SSteve Glendinning 		return ret;
1640e3c678e6SSteve Glendinning 	}
16419deb2757SSteve Glendinning 
16429deb2757SSteve Glendinning 	val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
16439deb2757SSteve Glendinning 	val |= PMT_CTL_SUS_MODE_2;
16449deb2757SSteve Glendinning 
16459deb2757SSteve Glendinning 	ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1646e3c678e6SSteve Glendinning 	if (ret < 0) {
1647e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing PMT_CTL\n");
1648e3c678e6SSteve Glendinning 		return ret;
1649e3c678e6SSteve Glendinning 	}
16509deb2757SSteve Glendinning 
1651b4cdea9cSSteve Glendinning 	pdata->suspend_flags |= SUSPEND_SUSPEND2;
1652b4cdea9cSSteve Glendinning 
1653b4cdea9cSSteve Glendinning 	return 0;
1654b4cdea9cSSteve Glendinning }
1655b4cdea9cSSteve Glendinning 
smsc75xx_enter_suspend3(struct usbnet * dev)1656b4cdea9cSSteve Glendinning static int smsc75xx_enter_suspend3(struct usbnet *dev)
1657b4cdea9cSSteve Glendinning {
1658b4cdea9cSSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
1659b4cdea9cSSteve Glendinning 	u32 val;
1660b4cdea9cSSteve Glendinning 	int ret;
1661b4cdea9cSSteve Glendinning 
1662b4cdea9cSSteve Glendinning 	ret = smsc75xx_read_reg_nopm(dev, FCT_RX_CTL, &val);
1663e3c678e6SSteve Glendinning 	if (ret < 0) {
1664e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading FCT_RX_CTL\n");
1665e3c678e6SSteve Glendinning 		return ret;
1666e3c678e6SSteve Glendinning 	}
1667b4cdea9cSSteve Glendinning 
1668b4cdea9cSSteve Glendinning 	if (val & FCT_RX_CTL_RXUSED) {
1669b4cdea9cSSteve Glendinning 		netdev_dbg(dev->net, "rx fifo not empty in autosuspend\n");
1670b4cdea9cSSteve Glendinning 		return -EBUSY;
1671b4cdea9cSSteve Glendinning 	}
1672b4cdea9cSSteve Glendinning 
1673b4cdea9cSSteve Glendinning 	ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
1674e3c678e6SSteve Glendinning 	if (ret < 0) {
1675e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading PMT_CTL\n");
1676e3c678e6SSteve Glendinning 		return ret;
1677e3c678e6SSteve Glendinning 	}
1678b4cdea9cSSteve Glendinning 
1679b4cdea9cSSteve Glendinning 	val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
1680b4cdea9cSSteve Glendinning 	val |= PMT_CTL_SUS_MODE_3 | PMT_CTL_RES_CLR_WKP_EN;
1681b4cdea9cSSteve Glendinning 
1682b4cdea9cSSteve Glendinning 	ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1683e3c678e6SSteve Glendinning 	if (ret < 0) {
1684e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing PMT_CTL\n");
1685e3c678e6SSteve Glendinning 		return ret;
1686e3c678e6SSteve Glendinning 	}
1687b4cdea9cSSteve Glendinning 
1688b4cdea9cSSteve Glendinning 	/* clear wol status */
1689b4cdea9cSSteve Glendinning 	val &= ~PMT_CTL_WUPS;
1690b4cdea9cSSteve Glendinning 	val |= PMT_CTL_WUPS_WOL;
1691b4cdea9cSSteve Glendinning 
1692b4cdea9cSSteve Glendinning 	ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1693e3c678e6SSteve Glendinning 	if (ret < 0) {
1694e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing PMT_CTL\n");
1695e3c678e6SSteve Glendinning 		return ret;
1696e3c678e6SSteve Glendinning 	}
1697b4cdea9cSSteve Glendinning 
1698351f33d9SSteve Glendinning 	pdata->suspend_flags |= SUSPEND_SUSPEND3;
1699b4cdea9cSSteve Glendinning 
17009deb2757SSteve Glendinning 	return 0;
17019deb2757SSteve Glendinning }
17029deb2757SSteve Glendinning 
smsc75xx_enable_phy_wakeup_interrupts(struct usbnet * dev,u16 mask)1703f329ccdcSSteve Glendinning static int smsc75xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask)
1704f329ccdcSSteve Glendinning {
1705f329ccdcSSteve Glendinning 	struct mii_if_info *mii = &dev->mii;
1706f329ccdcSSteve Glendinning 	int ret;
1707f329ccdcSSteve Glendinning 
1708f329ccdcSSteve Glendinning 	netdev_dbg(dev->net, "enabling PHY wakeup interrupts\n");
1709f329ccdcSSteve Glendinning 
1710f329ccdcSSteve Glendinning 	/* read to clear */
1711f329ccdcSSteve Glendinning 	ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC);
1712e3c678e6SSteve Glendinning 	if (ret < 0) {
1713e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
1714e3c678e6SSteve Glendinning 		return ret;
1715e3c678e6SSteve Glendinning 	}
1716f329ccdcSSteve Glendinning 
1717f329ccdcSSteve Glendinning 	/* enable interrupt source */
1718f329ccdcSSteve Glendinning 	ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK);
1719e3c678e6SSteve Glendinning 	if (ret < 0) {
1720e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading PHY_INT_MASK\n");
1721e3c678e6SSteve Glendinning 		return ret;
1722e3c678e6SSteve Glendinning 	}
1723f329ccdcSSteve Glendinning 
1724f329ccdcSSteve Glendinning 	ret |= mask;
1725f329ccdcSSteve Glendinning 
1726f329ccdcSSteve Glendinning 	smsc75xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_INT_MASK, ret);
1727f329ccdcSSteve Glendinning 
1728f329ccdcSSteve Glendinning 	return 0;
1729f329ccdcSSteve Glendinning }
1730f329ccdcSSteve Glendinning 
smsc75xx_link_ok_nopm(struct usbnet * dev)1731f329ccdcSSteve Glendinning static int smsc75xx_link_ok_nopm(struct usbnet *dev)
1732f329ccdcSSteve Glendinning {
1733f329ccdcSSteve Glendinning 	struct mii_if_info *mii = &dev->mii;
1734f329ccdcSSteve Glendinning 	int ret;
1735f329ccdcSSteve Glendinning 
1736f329ccdcSSteve Glendinning 	/* first, a dummy read, needed to latch some MII phys */
1737f329ccdcSSteve Glendinning 	ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
1738e3c678e6SSteve Glendinning 	if (ret < 0) {
1739e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading MII_BMSR\n");
1740e3c678e6SSteve Glendinning 		return ret;
1741e3c678e6SSteve Glendinning 	}
1742f329ccdcSSteve Glendinning 
1743f329ccdcSSteve Glendinning 	ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
1744e3c678e6SSteve Glendinning 	if (ret < 0) {
1745e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading MII_BMSR\n");
1746e3c678e6SSteve Glendinning 		return ret;
1747e3c678e6SSteve Glendinning 	}
1748f329ccdcSSteve Glendinning 
1749f329ccdcSSteve Glendinning 	return !!(ret & BMSR_LSTATUS);
1750f329ccdcSSteve Glendinning }
1751f329ccdcSSteve Glendinning 
smsc75xx_autosuspend(struct usbnet * dev,u32 link_up)1752b4cdea9cSSteve Glendinning static int smsc75xx_autosuspend(struct usbnet *dev, u32 link_up)
1753b4cdea9cSSteve Glendinning {
1754b4cdea9cSSteve Glendinning 	int ret;
1755b4cdea9cSSteve Glendinning 
1756b4cdea9cSSteve Glendinning 	if (!netif_running(dev->net)) {
1757b4cdea9cSSteve Glendinning 		/* interface is ifconfig down so fully power down hw */
1758b4cdea9cSSteve Glendinning 		netdev_dbg(dev->net, "autosuspend entering SUSPEND2\n");
1759b4cdea9cSSteve Glendinning 		return smsc75xx_enter_suspend2(dev);
1760b4cdea9cSSteve Glendinning 	}
1761b4cdea9cSSteve Glendinning 
1762b4cdea9cSSteve Glendinning 	if (!link_up) {
1763b4cdea9cSSteve Glendinning 		/* link is down so enter EDPD mode */
1764b4cdea9cSSteve Glendinning 		netdev_dbg(dev->net, "autosuspend entering SUSPEND1\n");
1765b4cdea9cSSteve Glendinning 
1766b4cdea9cSSteve Glendinning 		/* enable PHY wakeup events for if cable is attached */
1767b4cdea9cSSteve Glendinning 		ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
1768b4cdea9cSSteve Glendinning 			PHY_INT_MASK_ANEG_COMP);
1769e3c678e6SSteve Glendinning 		if (ret < 0) {
1770e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
1771e3c678e6SSteve Glendinning 			return ret;
1772e3c678e6SSteve Glendinning 		}
1773b4cdea9cSSteve Glendinning 
1774b4cdea9cSSteve Glendinning 		netdev_info(dev->net, "entering SUSPEND1 mode\n");
1775b4cdea9cSSteve Glendinning 		return smsc75xx_enter_suspend1(dev);
1776b4cdea9cSSteve Glendinning 	}
1777b4cdea9cSSteve Glendinning 
1778b4cdea9cSSteve Glendinning 	/* enable PHY wakeup events so we remote wakeup if cable is pulled */
1779b4cdea9cSSteve Glendinning 	ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
1780b4cdea9cSSteve Glendinning 		PHY_INT_MASK_LINK_DOWN);
1781e3c678e6SSteve Glendinning 	if (ret < 0) {
1782e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
1783e3c678e6SSteve Glendinning 		return ret;
1784e3c678e6SSteve Glendinning 	}
1785b4cdea9cSSteve Glendinning 
1786b4cdea9cSSteve Glendinning 	netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n");
1787b4cdea9cSSteve Glendinning 	return smsc75xx_enter_suspend3(dev);
1788b4cdea9cSSteve Glendinning }
1789b4cdea9cSSteve Glendinning 
smsc75xx_suspend(struct usb_interface * intf,pm_message_t message)179016c79a04SSteve Glendinning static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
179116c79a04SSteve Glendinning {
179216c79a04SSteve Glendinning 	struct usbnet *dev = usb_get_intfdata(intf);
17936c636503SSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
1794f329ccdcSSteve Glendinning 	u32 val, link_up;
179516c79a04SSteve Glendinning 	int ret;
179616c79a04SSteve Glendinning 
179716c79a04SSteve Glendinning 	ret = usbnet_suspend(intf, message);
1798e3c678e6SSteve Glendinning 	if (ret < 0) {
1799e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "usbnet_suspend error\n");
1800e3c678e6SSteve Glendinning 		return ret;
1801e3c678e6SSteve Glendinning 	}
180216c79a04SSteve Glendinning 
1803b4cdea9cSSteve Glendinning 	if (pdata->suspend_flags) {
1804b4cdea9cSSteve Glendinning 		netdev_warn(dev->net, "error during last resume\n");
1805b4cdea9cSSteve Glendinning 		pdata->suspend_flags = 0;
1806b4cdea9cSSteve Glendinning 	}
1807b4cdea9cSSteve Glendinning 
1808f329ccdcSSteve Glendinning 	/* determine if link is up using only _nopm functions */
1809f329ccdcSSteve Glendinning 	link_up = smsc75xx_link_ok_nopm(dev);
1810f329ccdcSSteve Glendinning 
1811b4cdea9cSSteve Glendinning 	if (message.event == PM_EVENT_AUTO_SUSPEND) {
1812b4cdea9cSSteve Glendinning 		ret = smsc75xx_autosuspend(dev, link_up);
1813b4cdea9cSSteve Glendinning 		goto done;
1814b4cdea9cSSteve Glendinning 	}
1815b4cdea9cSSteve Glendinning 
1816b4cdea9cSSteve Glendinning 	/* if we get this far we're not autosuspending */
1817f329ccdcSSteve Glendinning 	/* if no wol options set, or if link is down and we're not waking on
1818f329ccdcSSteve Glendinning 	 * PHY activity, enter lowest power SUSPEND2 mode
1819f329ccdcSSteve Glendinning 	 */
1820f329ccdcSSteve Glendinning 	if (!(pdata->wolopts & SUPPORTED_WAKE) ||
1821f329ccdcSSteve Glendinning 		!(link_up || (pdata->wolopts & WAKE_PHY))) {
18221e1d7412SJoe Perches 		netdev_info(dev->net, "entering SUSPEND2 mode\n");
182316c79a04SSteve Glendinning 
18246c636503SSteve Glendinning 		/* disable energy detect (link up) & wake up events */
182547bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
1826e3c678e6SSteve Glendinning 		if (ret < 0) {
1827e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading WUCSR\n");
1828e3c678e6SSteve Glendinning 			goto done;
1829e3c678e6SSteve Glendinning 		}
18306c636503SSteve Glendinning 
18316c636503SSteve Glendinning 		val &= ~(WUCSR_MPEN | WUCSR_WUEN);
18326c636503SSteve Glendinning 
183347bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
1834e3c678e6SSteve Glendinning 		if (ret < 0) {
1835e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing WUCSR\n");
1836e3c678e6SSteve Glendinning 			goto done;
1837e3c678e6SSteve Glendinning 		}
18386c636503SSteve Glendinning 
183947bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
1840e3c678e6SSteve Glendinning 		if (ret < 0) {
1841e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading PMT_CTL\n");
1842e3c678e6SSteve Glendinning 			goto done;
1843e3c678e6SSteve Glendinning 		}
18446c636503SSteve Glendinning 
18456c636503SSteve Glendinning 		val &= ~(PMT_CTL_ED_EN | PMT_CTL_WOL_EN);
18466c636503SSteve Glendinning 
184747bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1848e3c678e6SSteve Glendinning 		if (ret < 0) {
1849e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing PMT_CTL\n");
1850e3c678e6SSteve Glendinning 			goto done;
1851e3c678e6SSteve Glendinning 		}
18526c636503SSteve Glendinning 
1853eacdd6c2SSteve Glendinning 		ret = smsc75xx_enter_suspend2(dev);
1854eacdd6c2SSteve Glendinning 		goto done;
185516c79a04SSteve Glendinning 	}
185616c79a04SSteve Glendinning 
1857f329ccdcSSteve Glendinning 	if (pdata->wolopts & WAKE_PHY) {
1858f329ccdcSSteve Glendinning 		ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
1859f329ccdcSSteve Glendinning 			(PHY_INT_MASK_ANEG_COMP | PHY_INT_MASK_LINK_DOWN));
1860e3c678e6SSteve Glendinning 		if (ret < 0) {
1861e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
1862e3c678e6SSteve Glendinning 			goto done;
1863e3c678e6SSteve Glendinning 		}
1864f329ccdcSSteve Glendinning 
1865f329ccdcSSteve Glendinning 		/* if link is down then configure EDPD and enter SUSPEND1,
1866f329ccdcSSteve Glendinning 		 * otherwise enter SUSPEND0 below
1867f329ccdcSSteve Glendinning 		 */
1868f329ccdcSSteve Glendinning 		if (!link_up) {
1869f329ccdcSSteve Glendinning 			struct mii_if_info *mii = &dev->mii;
1870f329ccdcSSteve Glendinning 			netdev_info(dev->net, "entering SUSPEND1 mode\n");
1871f329ccdcSSteve Glendinning 
1872f329ccdcSSteve Glendinning 			/* enable energy detect power-down mode */
1873f329ccdcSSteve Glendinning 			ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id,
1874f329ccdcSSteve Glendinning 				PHY_MODE_CTRL_STS);
1875e3c678e6SSteve Glendinning 			if (ret < 0) {
1876e3c678e6SSteve Glendinning 				netdev_warn(dev->net, "Error reading PHY_MODE_CTRL_STS\n");
1877e3c678e6SSteve Glendinning 				goto done;
1878e3c678e6SSteve Glendinning 			}
1879f329ccdcSSteve Glendinning 
1880f329ccdcSSteve Glendinning 			ret |= MODE_CTRL_STS_EDPWRDOWN;
1881f329ccdcSSteve Glendinning 
1882f329ccdcSSteve Glendinning 			smsc75xx_mdio_write_nopm(dev->net, mii->phy_id,
1883f329ccdcSSteve Glendinning 				PHY_MODE_CTRL_STS, ret);
1884f329ccdcSSteve Glendinning 
1885f329ccdcSSteve Glendinning 			/* enter SUSPEND1 mode */
1886eacdd6c2SSteve Glendinning 			ret = smsc75xx_enter_suspend1(dev);
1887eacdd6c2SSteve Glendinning 			goto done;
1888f329ccdcSSteve Glendinning 		}
1889f329ccdcSSteve Glendinning 	}
1890f329ccdcSSteve Glendinning 
1891899a391bSSteve Glendinning 	if (pdata->wolopts & (WAKE_MCAST | WAKE_ARP)) {
1892899a391bSSteve Glendinning 		int i, filter = 0;
1893899a391bSSteve Glendinning 
1894899a391bSSteve Glendinning 		/* disable all filters */
1895899a391bSSteve Glendinning 		for (i = 0; i < WUF_NUM; i++) {
189647bbea41SMing Lei 			ret = smsc75xx_write_reg_nopm(dev, WUF_CFGX + i * 4, 0);
1897e3c678e6SSteve Glendinning 			if (ret < 0) {
1898e3c678e6SSteve Glendinning 				netdev_warn(dev->net, "Error writing WUF_CFGX\n");
1899e3c678e6SSteve Glendinning 				goto done;
1900e3c678e6SSteve Glendinning 			}
1901899a391bSSteve Glendinning 		}
1902899a391bSSteve Glendinning 
1903899a391bSSteve Glendinning 		if (pdata->wolopts & WAKE_MCAST) {
1904899a391bSSteve Glendinning 			const u8 mcast[] = {0x01, 0x00, 0x5E};
19051e1d7412SJoe Perches 			netdev_info(dev->net, "enabling multicast detection\n");
1906899a391bSSteve Glendinning 
1907899a391bSSteve Glendinning 			val = WUF_CFGX_EN | WUF_CFGX_ATYPE_MULTICAST
1908899a391bSSteve Glendinning 				| smsc_crc(mcast, 3);
1909899a391bSSteve Glendinning 			ret = smsc75xx_write_wuff(dev, filter++, val, 0x0007);
1910e3c678e6SSteve Glendinning 			if (ret < 0) {
1911e3c678e6SSteve Glendinning 				netdev_warn(dev->net, "Error writing wakeup filter\n");
1912e3c678e6SSteve Glendinning 				goto done;
1913e3c678e6SSteve Glendinning 			}
1914899a391bSSteve Glendinning 		}
1915899a391bSSteve Glendinning 
1916899a391bSSteve Glendinning 		if (pdata->wolopts & WAKE_ARP) {
1917899a391bSSteve Glendinning 			const u8 arp[] = {0x08, 0x06};
19181e1d7412SJoe Perches 			netdev_info(dev->net, "enabling ARP detection\n");
1919899a391bSSteve Glendinning 
1920899a391bSSteve Glendinning 			val = WUF_CFGX_EN | WUF_CFGX_ATYPE_ALL | (0x0C << 16)
1921899a391bSSteve Glendinning 				| smsc_crc(arp, 2);
1922899a391bSSteve Glendinning 			ret = smsc75xx_write_wuff(dev, filter++, val, 0x0003);
1923e3c678e6SSteve Glendinning 			if (ret < 0) {
1924e3c678e6SSteve Glendinning 				netdev_warn(dev->net, "Error writing wakeup filter\n");
1925e3c678e6SSteve Glendinning 				goto done;
1926e3c678e6SSteve Glendinning 			}
1927899a391bSSteve Glendinning 		}
1928899a391bSSteve Glendinning 
1929899a391bSSteve Glendinning 		/* clear any pending pattern match packet status */
193047bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
1931e3c678e6SSteve Glendinning 		if (ret < 0) {
1932e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading WUCSR\n");
1933e3c678e6SSteve Glendinning 			goto done;
1934e3c678e6SSteve Glendinning 		}
19356c636503SSteve Glendinning 
1936899a391bSSteve Glendinning 		val |= WUCSR_WUFR;
1937899a391bSSteve Glendinning 
193847bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
1939e3c678e6SSteve Glendinning 		if (ret < 0) {
1940e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing WUCSR\n");
1941e3c678e6SSteve Glendinning 			goto done;
1942e3c678e6SSteve Glendinning 		}
1943899a391bSSteve Glendinning 
19441e1d7412SJoe Perches 		netdev_info(dev->net, "enabling packet match detection\n");
194547bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
1946e3c678e6SSteve Glendinning 		if (ret < 0) {
1947e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading WUCSR\n");
1948e3c678e6SSteve Glendinning 			goto done;
1949e3c678e6SSteve Glendinning 		}
1950899a391bSSteve Glendinning 
1951899a391bSSteve Glendinning 		val |= WUCSR_WUEN;
1952899a391bSSteve Glendinning 
195347bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
1954e3c678e6SSteve Glendinning 		if (ret < 0) {
1955e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing WUCSR\n");
1956e3c678e6SSteve Glendinning 			goto done;
1957e3c678e6SSteve Glendinning 		}
1958899a391bSSteve Glendinning 	} else {
19591e1d7412SJoe Perches 		netdev_info(dev->net, "disabling packet match detection\n");
196047bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
1961e3c678e6SSteve Glendinning 		if (ret < 0) {
1962e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading WUCSR\n");
1963e3c678e6SSteve Glendinning 			goto done;
1964e3c678e6SSteve Glendinning 		}
1965899a391bSSteve Glendinning 
1966899a391bSSteve Glendinning 		val &= ~WUCSR_WUEN;
19676c636503SSteve Glendinning 
196847bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
1969e3c678e6SSteve Glendinning 		if (ret < 0) {
1970e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing WUCSR\n");
1971e3c678e6SSteve Glendinning 			goto done;
1972e3c678e6SSteve Glendinning 		}
19736c636503SSteve Glendinning 	}
19746c636503SSteve Glendinning 
1975899a391bSSteve Glendinning 	/* disable magic, bcast & unicast wakeup sources */
197647bbea41SMing Lei 	ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
1977e3c678e6SSteve Glendinning 	if (ret < 0) {
1978e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error reading WUCSR\n");
1979e3c678e6SSteve Glendinning 		goto done;
1980e3c678e6SSteve Glendinning 	}
19816c636503SSteve Glendinning 
1982899a391bSSteve Glendinning 	val &= ~(WUCSR_MPEN | WUCSR_BCST_EN | WUCSR_PFDA_EN);
1983899a391bSSteve Glendinning 
198447bbea41SMing Lei 	ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
1985e3c678e6SSteve Glendinning 	if (ret < 0) {
1986e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Error writing WUCSR\n");
1987e3c678e6SSteve Glendinning 		goto done;
1988e3c678e6SSteve Glendinning 	}
1989899a391bSSteve Glendinning 
1990f329ccdcSSteve Glendinning 	if (pdata->wolopts & WAKE_PHY) {
1991f329ccdcSSteve Glendinning 		netdev_info(dev->net, "enabling PHY wakeup\n");
1992f329ccdcSSteve Glendinning 
1993f329ccdcSSteve Glendinning 		ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
1994e3c678e6SSteve Glendinning 		if (ret < 0) {
1995e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading PMT_CTL\n");
1996e3c678e6SSteve Glendinning 			goto done;
1997e3c678e6SSteve Glendinning 		}
1998f329ccdcSSteve Glendinning 
1999f329ccdcSSteve Glendinning 		/* clear wol status, enable energy detection */
2000f329ccdcSSteve Glendinning 		val &= ~PMT_CTL_WUPS;
2001f329ccdcSSteve Glendinning 		val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN);
2002f329ccdcSSteve Glendinning 
2003f329ccdcSSteve Glendinning 		ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
2004e3c678e6SSteve Glendinning 		if (ret < 0) {
2005e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing PMT_CTL\n");
2006e3c678e6SSteve Glendinning 			goto done;
2007e3c678e6SSteve Glendinning 		}
2008f329ccdcSSteve Glendinning 	}
2009f329ccdcSSteve Glendinning 
20106c636503SSteve Glendinning 	if (pdata->wolopts & WAKE_MAGIC) {
20111e1d7412SJoe Perches 		netdev_info(dev->net, "enabling magic packet wakeup\n");
201247bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
2013e3c678e6SSteve Glendinning 		if (ret < 0) {
2014e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading WUCSR\n");
2015e3c678e6SSteve Glendinning 			goto done;
2016e3c678e6SSteve Glendinning 		}
2017899a391bSSteve Glendinning 
2018899a391bSSteve Glendinning 		/* clear any pending magic packet status */
2019899a391bSSteve Glendinning 		val |= WUCSR_MPR | WUCSR_MPEN;
20206c636503SSteve Glendinning 
202147bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
2022e3c678e6SSteve Glendinning 		if (ret < 0) {
2023e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing WUCSR\n");
2024e3c678e6SSteve Glendinning 			goto done;
2025e3c678e6SSteve Glendinning 		}
2026899a391bSSteve Glendinning 	}
20276c636503SSteve Glendinning 
2028899a391bSSteve Glendinning 	if (pdata->wolopts & WAKE_BCAST) {
20291e1d7412SJoe Perches 		netdev_info(dev->net, "enabling broadcast detection\n");
203047bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
2031e3c678e6SSteve Glendinning 		if (ret < 0) {
2032e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading WUCSR\n");
2033e3c678e6SSteve Glendinning 			goto done;
2034e3c678e6SSteve Glendinning 		}
20356c636503SSteve Glendinning 
2036899a391bSSteve Glendinning 		val |= WUCSR_BCAST_FR | WUCSR_BCST_EN;
20376c636503SSteve Glendinning 
203847bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
2039e3c678e6SSteve Glendinning 		if (ret < 0) {
2040e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing WUCSR\n");
2041e3c678e6SSteve Glendinning 			goto done;
2042e3c678e6SSteve Glendinning 		}
2043899a391bSSteve Glendinning 	}
20446c636503SSteve Glendinning 
2045899a391bSSteve Glendinning 	if (pdata->wolopts & WAKE_UCAST) {
20461e1d7412SJoe Perches 		netdev_info(dev->net, "enabling unicast detection\n");
204747bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
2048e3c678e6SSteve Glendinning 		if (ret < 0) {
2049e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading WUCSR\n");
2050e3c678e6SSteve Glendinning 			goto done;
2051e3c678e6SSteve Glendinning 		}
2052899a391bSSteve Glendinning 
2053899a391bSSteve Glendinning 		val |= WUCSR_WUFR | WUCSR_PFDA_EN;
2054899a391bSSteve Glendinning 
205547bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
2056e3c678e6SSteve Glendinning 		if (ret < 0) {
2057e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing WUCSR\n");
2058e3c678e6SSteve Glendinning 			goto done;
2059e3c678e6SSteve Glendinning 		}
2060899a391bSSteve Glendinning 	}
2061899a391bSSteve Glendinning 
2062899a391bSSteve Glendinning 	/* enable receiver to enable frame reception */
206347bbea41SMing Lei 	ret = smsc75xx_read_reg_nopm(dev, MAC_RX, &val);
2064e3c678e6SSteve Glendinning 	if (ret < 0) {
2065e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret);
2066e3c678e6SSteve Glendinning 		goto done;
2067e3c678e6SSteve Glendinning 	}
20686c636503SSteve Glendinning 
20696c636503SSteve Glendinning 	val |= MAC_RX_RXEN;
20706c636503SSteve Glendinning 
207147bbea41SMing Lei 	ret = smsc75xx_write_reg_nopm(dev, MAC_RX, val);
2072e3c678e6SSteve Glendinning 	if (ret < 0) {
2073e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
2074e3c678e6SSteve Glendinning 		goto done;
2075e3c678e6SSteve Glendinning 	}
20766c636503SSteve Glendinning 
20776c636503SSteve Glendinning 	/* some wol options are enabled, so enter SUSPEND0 */
20781e1d7412SJoe Perches 	netdev_info(dev->net, "entering SUSPEND0 mode\n");
2079eacdd6c2SSteve Glendinning 	ret = smsc75xx_enter_suspend0(dev);
2080eacdd6c2SSteve Glendinning 
2081eacdd6c2SSteve Glendinning done:
20825410a473SMing Lei 	/*
20835410a473SMing Lei 	 * TODO: resume() might need to handle the suspend failure
20845410a473SMing Lei 	 * in system sleep
20855410a473SMing Lei 	 */
20865410a473SMing Lei 	if (ret && PMSG_IS_AUTO(message))
2087eacdd6c2SSteve Glendinning 		usbnet_resume(intf);
2088eacdd6c2SSteve Glendinning 	return ret;
20896c636503SSteve Glendinning }
20906c636503SSteve Glendinning 
smsc75xx_resume(struct usb_interface * intf)209116c79a04SSteve Glendinning static int smsc75xx_resume(struct usb_interface *intf)
209216c79a04SSteve Glendinning {
209316c79a04SSteve Glendinning 	struct usbnet *dev = usb_get_intfdata(intf);
20946c636503SSteve Glendinning 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
2095b4cdea9cSSteve Glendinning 	u8 suspend_flags = pdata->suspend_flags;
209616c79a04SSteve Glendinning 	int ret;
209716c79a04SSteve Glendinning 	u32 val;
209816c79a04SSteve Glendinning 
2099b4cdea9cSSteve Glendinning 	netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags);
210016c79a04SSteve Glendinning 
2101b4cdea9cSSteve Glendinning 	/* do this first to ensure it's cleared even in error case */
2102b4cdea9cSSteve Glendinning 	pdata->suspend_flags = 0;
21036c636503SSteve Glendinning 
2104b4cdea9cSSteve Glendinning 	if (suspend_flags & SUSPEND_ALLMODES) {
2105899a391bSSteve Glendinning 		/* Disable wakeup sources */
210647bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
2107e3c678e6SSteve Glendinning 		if (ret < 0) {
2108e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading WUCSR\n");
2109e3c678e6SSteve Glendinning 			return ret;
2110e3c678e6SSteve Glendinning 		}
21116c636503SSteve Glendinning 
2112899a391bSSteve Glendinning 		val &= ~(WUCSR_WUEN | WUCSR_MPEN | WUCSR_PFDA_EN
2113899a391bSSteve Glendinning 			| WUCSR_BCST_EN);
21146c636503SSteve Glendinning 
211547bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
2116e3c678e6SSteve Glendinning 		if (ret < 0) {
2117e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing WUCSR\n");
2118e3c678e6SSteve Glendinning 			return ret;
2119e3c678e6SSteve Glendinning 		}
21206c636503SSteve Glendinning 
21216c636503SSteve Glendinning 		/* clear wake-up status */
212247bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
2123e3c678e6SSteve Glendinning 		if (ret < 0) {
2124e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading PMT_CTL\n");
2125e3c678e6SSteve Glendinning 			return ret;
2126e3c678e6SSteve Glendinning 		}
21276c636503SSteve Glendinning 
21286c636503SSteve Glendinning 		val &= ~PMT_CTL_WOL_EN;
21296c636503SSteve Glendinning 		val |= PMT_CTL_WUPS;
21306c636503SSteve Glendinning 
213147bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
2132e3c678e6SSteve Glendinning 		if (ret < 0) {
2133e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing PMT_CTL\n");
2134e3c678e6SSteve Glendinning 			return ret;
2135e3c678e6SSteve Glendinning 		}
2136b4cdea9cSSteve Glendinning 	}
2137b4cdea9cSSteve Glendinning 
2138b4cdea9cSSteve Glendinning 	if (suspend_flags & SUSPEND_SUSPEND2) {
21391e1d7412SJoe Perches 		netdev_info(dev->net, "resuming from SUSPEND2\n");
214016c79a04SSteve Glendinning 
214147bbea41SMing Lei 		ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
2142e3c678e6SSteve Glendinning 		if (ret < 0) {
2143e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error reading PMT_CTL\n");
2144e3c678e6SSteve Glendinning 			return ret;
2145e3c678e6SSteve Glendinning 		}
214616c79a04SSteve Glendinning 
214716c79a04SSteve Glendinning 		val |= PMT_CTL_PHY_PWRUP;
214816c79a04SSteve Glendinning 
214947bbea41SMing Lei 		ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
2150e3c678e6SSteve Glendinning 		if (ret < 0) {
2151e3c678e6SSteve Glendinning 			netdev_warn(dev->net, "Error writing PMT_CTL\n");
2152e3c678e6SSteve Glendinning 			return ret;
2153e3c678e6SSteve Glendinning 		}
21546c636503SSteve Glendinning 	}
215516c79a04SSteve Glendinning 
215647bbea41SMing Lei 	ret = smsc75xx_wait_ready(dev, 1);
2157e3c678e6SSteve Glendinning 	if (ret < 0) {
2158e3c678e6SSteve Glendinning 		netdev_warn(dev->net, "device not ready in smsc75xx_resume\n");
2159e3c678e6SSteve Glendinning 		return ret;
2160e3c678e6SSteve Glendinning 	}
216116c79a04SSteve Glendinning 
216216c79a04SSteve Glendinning 	return usbnet_resume(intf);
216316c79a04SSteve Glendinning }
216416c79a04SSteve Glendinning 
smsc75xx_rx_csum_offload(struct usbnet * dev,struct sk_buff * skb,u32 rx_cmd_a,u32 rx_cmd_b)216578e47fe4SMichał Mirosław static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb,
216678e47fe4SMichał Mirosław 				     u32 rx_cmd_a, u32 rx_cmd_b)
2167d0cad871SSteve Glendinning {
216878e47fe4SMichał Mirosław 	if (!(dev->net->features & NETIF_F_RXCSUM) ||
216978e47fe4SMichał Mirosław 	    unlikely(rx_cmd_a & RX_CMD_A_LCSM)) {
2170d0cad871SSteve Glendinning 		skb->ip_summed = CHECKSUM_NONE;
2171d0cad871SSteve Glendinning 	} else {
2172d0cad871SSteve Glendinning 		skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT));
2173d0cad871SSteve Glendinning 		skb->ip_summed = CHECKSUM_COMPLETE;
2174d0cad871SSteve Glendinning 	}
2175d0cad871SSteve Glendinning }
2176d0cad871SSteve Glendinning 
smsc75xx_rx_fixup(struct usbnet * dev,struct sk_buff * skb)2177d0cad871SSteve Glendinning static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
2178d0cad871SSteve Glendinning {
2179eb85569fSEmil Goode 	/* This check is no longer done by usbnet */
2180eb85569fSEmil Goode 	if (skb->len < dev->net->hard_header_len)
2181eb85569fSEmil Goode 		return 0;
2182eb85569fSEmil Goode 
2183d0cad871SSteve Glendinning 	while (skb->len > 0) {
2184d0cad871SSteve Glendinning 		u32 rx_cmd_a, rx_cmd_b, align_count, size;
2185d0cad871SSteve Glendinning 		struct sk_buff *ax_skb;
2186d0cad871SSteve Glendinning 		unsigned char *packet;
2187d0cad871SSteve Glendinning 
21885864118bSChuhong Yuan 		rx_cmd_a = get_unaligned_le32(skb->data);
2189d0cad871SSteve Glendinning 		skb_pull(skb, 4);
2190d0cad871SSteve Glendinning 
21915864118bSChuhong Yuan 		rx_cmd_b = get_unaligned_le32(skb->data);
2192ea1649deSNico Erfurth 		skb_pull(skb, 4 + RXW_PADDING);
2193d0cad871SSteve Glendinning 
2194d0cad871SSteve Glendinning 		packet = skb->data;
2195d0cad871SSteve Glendinning 
2196d0cad871SSteve Glendinning 		/* get the packet length */
2197ea1649deSNico Erfurth 		size = (rx_cmd_a & RX_CMD_A_LEN) - RXW_PADDING;
2198ea1649deSNico Erfurth 		align_count = (4 - ((size + RXW_PADDING) % 4)) % 4;
2199d0cad871SSteve Glendinning 
220043ffe6caSSzymon Heidrich 		if (unlikely(size > skb->len)) {
220143ffe6caSSzymon Heidrich 			netif_dbg(dev, rx_err, dev->net,
220243ffe6caSSzymon Heidrich 				  "size err rx_cmd_a=0x%08x\n",
220343ffe6caSSzymon Heidrich 				  rx_cmd_a);
220443ffe6caSSzymon Heidrich 			return 0;
220543ffe6caSSzymon Heidrich 		}
220643ffe6caSSzymon Heidrich 
2207d0cad871SSteve Glendinning 		if (unlikely(rx_cmd_a & RX_CMD_A_RED)) {
2208d0cad871SSteve Glendinning 			netif_dbg(dev, rx_err, dev->net,
22091e1d7412SJoe Perches 				  "Error rx_cmd_a=0x%08x\n", rx_cmd_a);
2210d0cad871SSteve Glendinning 			dev->net->stats.rx_errors++;
2211d0cad871SSteve Glendinning 			dev->net->stats.rx_dropped++;
2212d0cad871SSteve Glendinning 
2213d0cad871SSteve Glendinning 			if (rx_cmd_a & RX_CMD_A_FCS)
2214d0cad871SSteve Glendinning 				dev->net->stats.rx_crc_errors++;
2215d0cad871SSteve Glendinning 			else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT))
2216d0cad871SSteve Glendinning 				dev->net->stats.rx_frame_errors++;
2217d0cad871SSteve Glendinning 		} else {
22184c51e536SSteve Glendinning 			/* MAX_SINGLE_PACKET_SIZE + 4(CRC) + 2(COE) + 4(Vlan) */
221943ffe6caSSzymon Heidrich 			if (unlikely(size > (MAX_SINGLE_PACKET_SIZE + ETH_HLEN + 12))) {
2220d0cad871SSteve Glendinning 				netif_dbg(dev, rx_err, dev->net,
22211e1d7412SJoe Perches 					  "size err rx_cmd_a=0x%08x\n",
22221e1d7412SJoe Perches 					  rx_cmd_a);
2223d0cad871SSteve Glendinning 				return 0;
2224d0cad871SSteve Glendinning 			}
2225d0cad871SSteve Glendinning 
2226d0cad871SSteve Glendinning 			/* last frame in this batch */
2227d0cad871SSteve Glendinning 			if (skb->len == size) {
222878e47fe4SMichał Mirosław 				smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a,
2229d0cad871SSteve Glendinning 					rx_cmd_b);
2230d0cad871SSteve Glendinning 
2231d0cad871SSteve Glendinning 				skb_trim(skb, skb->len - 4); /* remove fcs */
2232d0cad871SSteve Glendinning 
2233d0cad871SSteve Glendinning 				return 1;
2234d0cad871SSteve Glendinning 			}
2235d0cad871SSteve Glendinning 
2236*1b3b2d9eSEric Dumazet 			/* Use "size - 4" to remove fcs */
2237*1b3b2d9eSEric Dumazet 			ax_skb = netdev_alloc_skb_ip_align(dev->net, size - 4);
2238d0cad871SSteve Glendinning 			if (unlikely(!ax_skb)) {
22391e1d7412SJoe Perches 				netdev_warn(dev->net, "Error allocating skb\n");
2240d0cad871SSteve Glendinning 				return 0;
2241d0cad871SSteve Glendinning 			}
2242d0cad871SSteve Glendinning 
2243*1b3b2d9eSEric Dumazet 			skb_put(ax_skb, size - 4);
2244*1b3b2d9eSEric Dumazet 			memcpy(ax_skb->data, packet, size - 4);
2245d0cad871SSteve Glendinning 
224678e47fe4SMichał Mirosław 			smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a,
2247d0cad871SSteve Glendinning 				rx_cmd_b);
2248d0cad871SSteve Glendinning 
2249d0cad871SSteve Glendinning 			usbnet_skb_return(dev, ax_skb);
2250d0cad871SSteve Glendinning 		}
2251d0cad871SSteve Glendinning 
2252d0cad871SSteve Glendinning 		skb_pull(skb, size);
2253d0cad871SSteve Glendinning 
2254d0cad871SSteve Glendinning 		/* padding bytes before the next frame starts */
2255d0cad871SSteve Glendinning 		if (skb->len)
2256d0cad871SSteve Glendinning 			skb_pull(skb, align_count);
2257d0cad871SSteve Glendinning 	}
2258d0cad871SSteve Glendinning 
2259d0cad871SSteve Glendinning 	return 1;
2260d0cad871SSteve Glendinning }
2261d0cad871SSteve Glendinning 
smsc75xx_tx_fixup(struct usbnet * dev,struct sk_buff * skb,gfp_t flags)2262d0cad871SSteve Glendinning static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev,
2263d0cad871SSteve Glendinning 					 struct sk_buff *skb, gfp_t flags)
2264d0cad871SSteve Glendinning {
2265d0cad871SSteve Glendinning 	u32 tx_cmd_a, tx_cmd_b;
22667e24b4edSChuhong Yuan 	void *ptr;
2267d0cad871SSteve Glendinning 
2268b7c6d267SEric Dumazet 	if (skb_cow_head(skb, SMSC75XX_TX_OVERHEAD)) {
2269d0cad871SSteve Glendinning 		dev_kfree_skb_any(skb);
2270d0cad871SSteve Glendinning 		return NULL;
2271d0cad871SSteve Glendinning 	}
2272d0cad871SSteve Glendinning 
2273d0cad871SSteve Glendinning 	tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS;
2274d0cad871SSteve Glendinning 
2275d0cad871SSteve Glendinning 	if (skb->ip_summed == CHECKSUM_PARTIAL)
2276d0cad871SSteve Glendinning 		tx_cmd_a |= TX_CMD_A_IPE | TX_CMD_A_TPE;
2277d0cad871SSteve Glendinning 
2278d0cad871SSteve Glendinning 	if (skb_is_gso(skb)) {
2279d0cad871SSteve Glendinning 		u16 mss = max(skb_shinfo(skb)->gso_size, TX_MSS_MIN);
2280d0cad871SSteve Glendinning 		tx_cmd_b = (mss << TX_CMD_B_MSS_SHIFT) & TX_CMD_B_MSS;
2281d0cad871SSteve Glendinning 
2282d0cad871SSteve Glendinning 		tx_cmd_a |= TX_CMD_A_LSO;
2283d0cad871SSteve Glendinning 	} else {
2284d0cad871SSteve Glendinning 		tx_cmd_b = 0;
2285d0cad871SSteve Glendinning 	}
2286d0cad871SSteve Glendinning 
22877e24b4edSChuhong Yuan 	ptr = skb_push(skb, 8);
22887e24b4edSChuhong Yuan 	put_unaligned_le32(tx_cmd_a, ptr);
22897e24b4edSChuhong Yuan 	put_unaligned_le32(tx_cmd_b, ptr + 4);
2290d0cad871SSteve Glendinning 
2291d0cad871SSteve Glendinning 	return skb;
2292d0cad871SSteve Glendinning }
2293d0cad871SSteve Glendinning 
smsc75xx_manage_power(struct usbnet * dev,int on)2294b4cdea9cSSteve Glendinning static int smsc75xx_manage_power(struct usbnet *dev, int on)
2295b4cdea9cSSteve Glendinning {
2296b4cdea9cSSteve Glendinning 	dev->intf->needs_remote_wakeup = on;
2297b4cdea9cSSteve Glendinning 	return 0;
2298b4cdea9cSSteve Glendinning }
2299b4cdea9cSSteve Glendinning 
2300d0cad871SSteve Glendinning static const struct driver_info smsc75xx_info = {
2301d0cad871SSteve Glendinning 	.description	= "smsc75xx USB 2.0 Gigabit Ethernet",
2302d0cad871SSteve Glendinning 	.bind		= smsc75xx_bind,
2303d0cad871SSteve Glendinning 	.unbind		= smsc75xx_unbind,
2304d0cad871SSteve Glendinning 	.link_reset	= smsc75xx_link_reset,
2305d0cad871SSteve Glendinning 	.reset		= smsc75xx_reset,
2306d0cad871SSteve Glendinning 	.rx_fixup	= smsc75xx_rx_fixup,
2307d0cad871SSteve Glendinning 	.tx_fixup	= smsc75xx_tx_fixup,
2308d0cad871SSteve Glendinning 	.status		= smsc75xx_status,
2309b4cdea9cSSteve Glendinning 	.manage_power	= smsc75xx_manage_power,
23107bdd305eSSteve Glendinning 	.flags		= FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR,
2311d0cad871SSteve Glendinning };
2312d0cad871SSteve Glendinning 
2313d0cad871SSteve Glendinning static const struct usb_device_id products[] = {
2314d0cad871SSteve Glendinning 	{
2315d0cad871SSteve Glendinning 		/* SMSC7500 USB Gigabit Ethernet Device */
2316d0cad871SSteve Glendinning 		USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7500),
2317d0cad871SSteve Glendinning 		.driver_info = (unsigned long) &smsc75xx_info,
2318d0cad871SSteve Glendinning 	},
2319d0cad871SSteve Glendinning 	{
2320d0cad871SSteve Glendinning 		/* SMSC7500 USB Gigabit Ethernet Device */
2321d0cad871SSteve Glendinning 		USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7505),
2322d0cad871SSteve Glendinning 		.driver_info = (unsigned long) &smsc75xx_info,
2323d0cad871SSteve Glendinning 	},
2324d0cad871SSteve Glendinning 	{ },		/* END */
2325d0cad871SSteve Glendinning };
2326d0cad871SSteve Glendinning MODULE_DEVICE_TABLE(usb, products);
2327d0cad871SSteve Glendinning 
2328d0cad871SSteve Glendinning static struct usb_driver smsc75xx_driver = {
2329d0cad871SSteve Glendinning 	.name		= SMSC_CHIPNAME,
2330d0cad871SSteve Glendinning 	.id_table	= products,
2331d0cad871SSteve Glendinning 	.probe		= usbnet_probe,
233216c79a04SSteve Glendinning 	.suspend	= smsc75xx_suspend,
233316c79a04SSteve Glendinning 	.resume		= smsc75xx_resume,
233416c79a04SSteve Glendinning 	.reset_resume	= smsc75xx_resume,
2335d0cad871SSteve Glendinning 	.disconnect	= usbnet_disconnect,
2336e1f12eb6SSarah Sharp 	.disable_hub_initiated_lpm = 1,
2337b4cdea9cSSteve Glendinning 	.supports_autosuspend = 1,
2338d0cad871SSteve Glendinning };
2339d0cad871SSteve Glendinning 
2340d632eb1bSGreg Kroah-Hartman module_usb_driver(smsc75xx_driver);
2341d0cad871SSteve Glendinning 
2342d0cad871SSteve Glendinning MODULE_AUTHOR("Nancy Lin");
234390b24cfbSSteve Glendinning MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>");
2344d0cad871SSteve Glendinning MODULE_DESCRIPTION("SMSC75XX USB 2.0 Gigabit Ethernet Devices");
2345d0cad871SSteve Glendinning MODULE_LICENSE("GPL");
2346