xref: /openbmc/linux/drivers/net/usb/sr9700.c (revision 323955a0498ccaa1263e369b91efd8f4310768b6)
1c9b37458SLiu Junliang /*
2c9b37458SLiu Junliang  * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
3c9b37458SLiu Junliang  *
4c9b37458SLiu Junliang  * Author : Liu Junliang <liujunliang_ljl@163.com>
5c9b37458SLiu Junliang  *
6c9b37458SLiu Junliang  * Based on dm9601.c
7c9b37458SLiu Junliang  *
8c9b37458SLiu Junliang  * This file is licensed under the terms of the GNU General Public License
9c9b37458SLiu Junliang  * version 2.  This program is licensed "as is" without any warranty of any
10c9b37458SLiu Junliang  * kind, whether express or implied.
11c9b37458SLiu Junliang  */
12c9b37458SLiu Junliang 
13c9b37458SLiu Junliang #include <linux/module.h>
14c9b37458SLiu Junliang #include <linux/sched.h>
15c9b37458SLiu Junliang #include <linux/stddef.h>
16c9b37458SLiu Junliang #include <linux/netdevice.h>
17c9b37458SLiu Junliang #include <linux/etherdevice.h>
18c9b37458SLiu Junliang #include <linux/ethtool.h>
19c9b37458SLiu Junliang #include <linux/mii.h>
20c9b37458SLiu Junliang #include <linux/usb.h>
21c9b37458SLiu Junliang #include <linux/crc32.h>
22c9b37458SLiu Junliang #include <linux/usb/usbnet.h>
23c9b37458SLiu Junliang 
24c9b37458SLiu Junliang #include "sr9700.h"
25c9b37458SLiu Junliang 
26c9b37458SLiu Junliang static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
27c9b37458SLiu Junliang {
28c9b37458SLiu Junliang 	int err;
29c9b37458SLiu Junliang 
30c9b37458SLiu Junliang 	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data,
31c9b37458SLiu Junliang 			      length);
32c9b37458SLiu Junliang 	if ((err != length) && (err >= 0))
33c9b37458SLiu Junliang 		err = -EINVAL;
34c9b37458SLiu Junliang 	return err;
35c9b37458SLiu Junliang }
36c9b37458SLiu Junliang 
37c9b37458SLiu Junliang static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
38c9b37458SLiu Junliang {
39c9b37458SLiu Junliang 	int err;
40c9b37458SLiu Junliang 
41c9b37458SLiu Junliang 	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, 0, reg, data,
42c9b37458SLiu Junliang 			       length);
43c9b37458SLiu Junliang 	if ((err >= 0) && (err < length))
44c9b37458SLiu Junliang 		err = -EINVAL;
45c9b37458SLiu Junliang 	return err;
46c9b37458SLiu Junliang }
47c9b37458SLiu Junliang 
48c9b37458SLiu Junliang static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
49c9b37458SLiu Junliang {
50c9b37458SLiu Junliang 	return sr_read(dev, reg, 1, value);
51c9b37458SLiu Junliang }
52c9b37458SLiu Junliang 
53c9b37458SLiu Junliang static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
54c9b37458SLiu Junliang {
55c9b37458SLiu Junliang 	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
56c9b37458SLiu Junliang 				value, reg, NULL, 0);
57c9b37458SLiu Junliang }
58c9b37458SLiu Junliang 
59c9b37458SLiu Junliang static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
60c9b37458SLiu Junliang {
61c9b37458SLiu Junliang 	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
62c9b37458SLiu Junliang 			       0, reg, data, length);
63c9b37458SLiu Junliang }
64c9b37458SLiu Junliang 
65c9b37458SLiu Junliang static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
66c9b37458SLiu Junliang {
67c9b37458SLiu Junliang 	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
68c9b37458SLiu Junliang 			       value, reg, NULL, 0);
69c9b37458SLiu Junliang }
70c9b37458SLiu Junliang 
71c9b37458SLiu Junliang static int wait_phy_eeprom_ready(struct usbnet *dev, int phy)
72c9b37458SLiu Junliang {
73c9b37458SLiu Junliang 	int i;
74c9b37458SLiu Junliang 
75c9b37458SLiu Junliang 	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
76c9b37458SLiu Junliang 		u8 tmp = 0;
77c9b37458SLiu Junliang 		int ret;
78c9b37458SLiu Junliang 
79c9b37458SLiu Junliang 		udelay(1);
8006b19b1bSChen Gang 		ret = sr_read_reg(dev, SR_EPCR, &tmp);
81c9b37458SLiu Junliang 		if (ret < 0)
82c9b37458SLiu Junliang 			return ret;
83c9b37458SLiu Junliang 
84c9b37458SLiu Junliang 		/* ready */
85c9b37458SLiu Junliang 		if (!(tmp & EPCR_ERRE))
86c9b37458SLiu Junliang 			return 0;
87c9b37458SLiu Junliang 	}
88c9b37458SLiu Junliang 
89c9b37458SLiu Junliang 	netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
90c9b37458SLiu Junliang 
91c9b37458SLiu Junliang 	return -EIO;
92c9b37458SLiu Junliang }
93c9b37458SLiu Junliang 
94c9b37458SLiu Junliang static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
95c9b37458SLiu Junliang 			      __le16 *value)
96c9b37458SLiu Junliang {
97c9b37458SLiu Junliang 	int ret;
98c9b37458SLiu Junliang 
99c9b37458SLiu Junliang 	mutex_lock(&dev->phy_mutex);
100c9b37458SLiu Junliang 
10106b19b1bSChen Gang 	sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
10206b19b1bSChen Gang 	sr_write_reg(dev, SR_EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR);
103c9b37458SLiu Junliang 
104c9b37458SLiu Junliang 	ret = wait_phy_eeprom_ready(dev, phy);
105c9b37458SLiu Junliang 	if (ret < 0)
106c9b37458SLiu Junliang 		goto out_unlock;
107c9b37458SLiu Junliang 
10806b19b1bSChen Gang 	sr_write_reg(dev, SR_EPCR, 0x0);
10906b19b1bSChen Gang 	ret = sr_read(dev, SR_EPDR, 2, value);
110c9b37458SLiu Junliang 
111c9b37458SLiu Junliang 	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
112c9b37458SLiu Junliang 		   phy, reg, *value, ret);
113c9b37458SLiu Junliang 
114c9b37458SLiu Junliang out_unlock:
115c9b37458SLiu Junliang 	mutex_unlock(&dev->phy_mutex);
116c9b37458SLiu Junliang 	return ret;
117c9b37458SLiu Junliang }
118c9b37458SLiu Junliang 
119c9b37458SLiu Junliang static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg,
120c9b37458SLiu Junliang 			       __le16 value)
121c9b37458SLiu Junliang {
122c9b37458SLiu Junliang 	int ret;
123c9b37458SLiu Junliang 
124c9b37458SLiu Junliang 	mutex_lock(&dev->phy_mutex);
125c9b37458SLiu Junliang 
12606b19b1bSChen Gang 	ret = sr_write(dev, SR_EPDR, 2, &value);
127c9b37458SLiu Junliang 	if (ret < 0)
128c9b37458SLiu Junliang 		goto out_unlock;
129c9b37458SLiu Junliang 
13006b19b1bSChen Gang 	sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
13106b19b1bSChen Gang 	sr_write_reg(dev, SR_EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) :
132c9b37458SLiu Junliang 		    (EPCR_WEP | EPCR_ERPRW));
133c9b37458SLiu Junliang 
134c9b37458SLiu Junliang 	ret = wait_phy_eeprom_ready(dev, phy);
135c9b37458SLiu Junliang 	if (ret < 0)
136c9b37458SLiu Junliang 		goto out_unlock;
137c9b37458SLiu Junliang 
13806b19b1bSChen Gang 	sr_write_reg(dev, SR_EPCR, 0x0);
139c9b37458SLiu Junliang 
140c9b37458SLiu Junliang out_unlock:
141c9b37458SLiu Junliang 	mutex_unlock(&dev->phy_mutex);
142c9b37458SLiu Junliang 	return ret;
143c9b37458SLiu Junliang }
144c9b37458SLiu Junliang 
145c9b37458SLiu Junliang static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
146c9b37458SLiu Junliang {
147c9b37458SLiu Junliang 	return sr_share_read_word(dev, 0, offset, value);
148c9b37458SLiu Junliang }
149c9b37458SLiu Junliang 
150c9b37458SLiu Junliang static int sr9700_get_eeprom_len(struct net_device *netdev)
151c9b37458SLiu Junliang {
152c9b37458SLiu Junliang 	return SR_EEPROM_LEN;
153c9b37458SLiu Junliang }
154c9b37458SLiu Junliang 
155c9b37458SLiu Junliang static int sr9700_get_eeprom(struct net_device *netdev,
156c9b37458SLiu Junliang 			     struct ethtool_eeprom *eeprom, u8 *data)
157c9b37458SLiu Junliang {
158c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
159c9b37458SLiu Junliang 	__le16 *buf = (__le16 *)data;
160c9b37458SLiu Junliang 	int ret = 0;
161c9b37458SLiu Junliang 	int i;
162c9b37458SLiu Junliang 
163c9b37458SLiu Junliang 	/* access is 16bit */
164c9b37458SLiu Junliang 	if ((eeprom->offset & 0x01) || (eeprom->len & 0x01))
165c9b37458SLiu Junliang 		return -EINVAL;
166c9b37458SLiu Junliang 
167c9b37458SLiu Junliang 	for (i = 0; i < eeprom->len / 2; i++) {
168c9b37458SLiu Junliang 		ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, buf + i);
169c9b37458SLiu Junliang 		if (ret < 0)
170c9b37458SLiu Junliang 			break;
171c9b37458SLiu Junliang 	}
172c9b37458SLiu Junliang 
173c9b37458SLiu Junliang 	return ret;
174c9b37458SLiu Junliang }
175c9b37458SLiu Junliang 
176c9b37458SLiu Junliang static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
177c9b37458SLiu Junliang {
178c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
179c9b37458SLiu Junliang 	__le16 res;
180c9b37458SLiu Junliang 	int rc = 0;
181c9b37458SLiu Junliang 
182c9b37458SLiu Junliang 	if (phy_id) {
183c9b37458SLiu Junliang 		netdev_dbg(netdev, "Only internal phy supported\n");
184c9b37458SLiu Junliang 		return 0;
185c9b37458SLiu Junliang 	}
186c9b37458SLiu Junliang 
187c9b37458SLiu Junliang 	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
188c9b37458SLiu Junliang 	if (loc == MII_BMSR) {
189c9b37458SLiu Junliang 		u8 value;
190c9b37458SLiu Junliang 
19106b19b1bSChen Gang 		sr_read_reg(dev, SR_NSR, &value);
192c9b37458SLiu Junliang 		if (value & NSR_LINKST)
193c9b37458SLiu Junliang 			rc = 1;
194c9b37458SLiu Junliang 	}
195c9b37458SLiu Junliang 	sr_share_read_word(dev, 1, loc, &res);
196c9b37458SLiu Junliang 	if (rc == 1)
197c9b37458SLiu Junliang 		res = le16_to_cpu(res) | BMSR_LSTATUS;
198c9b37458SLiu Junliang 	else
199c9b37458SLiu Junliang 		res = le16_to_cpu(res) & ~BMSR_LSTATUS;
200c9b37458SLiu Junliang 
201c9b37458SLiu Junliang 	netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
202c9b37458SLiu Junliang 		   phy_id, loc, res);
203c9b37458SLiu Junliang 
204c9b37458SLiu Junliang 	return res;
205c9b37458SLiu Junliang }
206c9b37458SLiu Junliang 
207c9b37458SLiu Junliang static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc,
208c9b37458SLiu Junliang 			  int val)
209c9b37458SLiu Junliang {
210c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
211c9b37458SLiu Junliang 	__le16 res = cpu_to_le16(val);
212c9b37458SLiu Junliang 
213c9b37458SLiu Junliang 	if (phy_id) {
214c9b37458SLiu Junliang 		netdev_dbg(netdev, "Only internal phy supported\n");
215c9b37458SLiu Junliang 		return;
216c9b37458SLiu Junliang 	}
217c9b37458SLiu Junliang 
218c9b37458SLiu Junliang 	netdev_dbg(netdev, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
219c9b37458SLiu Junliang 		   phy_id, loc, val);
220c9b37458SLiu Junliang 
221c9b37458SLiu Junliang 	sr_share_write_word(dev, 1, loc, res);
222c9b37458SLiu Junliang }
223c9b37458SLiu Junliang 
224c9b37458SLiu Junliang static u32 sr9700_get_link(struct net_device *netdev)
225c9b37458SLiu Junliang {
226c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
227c9b37458SLiu Junliang 	u8 value = 0;
228c9b37458SLiu Junliang 	int rc = 0;
229c9b37458SLiu Junliang 
230c9b37458SLiu Junliang 	/* Get the Link Status directly */
23106b19b1bSChen Gang 	sr_read_reg(dev, SR_NSR, &value);
232c9b37458SLiu Junliang 	if (value & NSR_LINKST)
233c9b37458SLiu Junliang 		rc = 1;
234c9b37458SLiu Junliang 
235c9b37458SLiu Junliang 	return rc;
236c9b37458SLiu Junliang }
237c9b37458SLiu Junliang 
238c9b37458SLiu Junliang static int sr9700_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
239c9b37458SLiu Junliang {
240c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
241c9b37458SLiu Junliang 
242c9b37458SLiu Junliang 	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
243c9b37458SLiu Junliang }
244c9b37458SLiu Junliang 
245c9b37458SLiu Junliang static const struct ethtool_ops sr9700_ethtool_ops = {
246c9b37458SLiu Junliang 	.get_drvinfo	= usbnet_get_drvinfo,
247c9b37458SLiu Junliang 	.get_link	= sr9700_get_link,
248c9b37458SLiu Junliang 	.get_msglevel	= usbnet_get_msglevel,
249c9b37458SLiu Junliang 	.set_msglevel	= usbnet_set_msglevel,
250c9b37458SLiu Junliang 	.get_eeprom_len	= sr9700_get_eeprom_len,
251c9b37458SLiu Junliang 	.get_eeprom	= sr9700_get_eeprom,
252c9b37458SLiu Junliang 	.nway_reset	= usbnet_nway_reset,
25339f49eadSPhilippe Reynes 	.get_link_ksettings	= usbnet_get_link_ksettings,
25439f49eadSPhilippe Reynes 	.set_link_ksettings	= usbnet_set_link_ksettings,
255c9b37458SLiu Junliang };
256c9b37458SLiu Junliang 
257c9b37458SLiu Junliang static void sr9700_set_multicast(struct net_device *netdev)
258c9b37458SLiu Junliang {
259c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
260c9b37458SLiu Junliang 	/* We use the 20 byte dev->data for our 8 byte filter buffer
261c9b37458SLiu Junliang 	 * to avoid allocating memory that is tricky to free later
262c9b37458SLiu Junliang 	 */
263c9b37458SLiu Junliang 	u8 *hashes = (u8 *)&dev->data;
264c9b37458SLiu Junliang 	/* rx_ctl setting : enable, disable_long, disable_crc */
265c9b37458SLiu Junliang 	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
266c9b37458SLiu Junliang 
267c9b37458SLiu Junliang 	memset(hashes, 0x00, SR_MCAST_SIZE);
268c9b37458SLiu Junliang 	/* broadcast address */
269c9b37458SLiu Junliang 	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;
270c9b37458SLiu Junliang 	if (netdev->flags & IFF_PROMISC) {
271c9b37458SLiu Junliang 		rx_ctl |= RCR_PRMSC;
272c9b37458SLiu Junliang 	} else if (netdev->flags & IFF_ALLMULTI ||
273c9b37458SLiu Junliang 		   netdev_mc_count(netdev) > SR_MCAST_MAX) {
274c9b37458SLiu Junliang 		rx_ctl |= RCR_RUNT;
275c9b37458SLiu Junliang 	} else if (!netdev_mc_empty(netdev)) {
276c9b37458SLiu Junliang 		struct netdev_hw_addr *ha;
277c9b37458SLiu Junliang 
278c9b37458SLiu Junliang 		netdev_for_each_mc_addr(ha, netdev) {
279c9b37458SLiu Junliang 			u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
280c9b37458SLiu Junliang 			hashes[crc >> 3] |= 1 << (crc & 0x7);
281c9b37458SLiu Junliang 		}
282c9b37458SLiu Junliang 	}
283c9b37458SLiu Junliang 
28406b19b1bSChen Gang 	sr_write_async(dev, SR_MAR, SR_MCAST_SIZE, hashes);
28506b19b1bSChen Gang 	sr_write_reg_async(dev, SR_RCR, rx_ctl);
286c9b37458SLiu Junliang }
287c9b37458SLiu Junliang 
288c9b37458SLiu Junliang static int sr9700_set_mac_address(struct net_device *netdev, void *p)
289c9b37458SLiu Junliang {
290c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
291c9b37458SLiu Junliang 	struct sockaddr *addr = p;
292c9b37458SLiu Junliang 
293c9b37458SLiu Junliang 	if (!is_valid_ether_addr(addr->sa_data)) {
294c9b37458SLiu Junliang 		netdev_err(netdev, "not setting invalid mac address %pM\n",
295c9b37458SLiu Junliang 			   addr->sa_data);
296c9b37458SLiu Junliang 		return -EINVAL;
297c9b37458SLiu Junliang 	}
298c9b37458SLiu Junliang 
299c9b37458SLiu Junliang 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
30006b19b1bSChen Gang 	sr_write_async(dev, SR_PAR, 6, netdev->dev_addr);
301c9b37458SLiu Junliang 
302c9b37458SLiu Junliang 	return 0;
303c9b37458SLiu Junliang }
304c9b37458SLiu Junliang 
305c9b37458SLiu Junliang static const struct net_device_ops sr9700_netdev_ops = {
306c9b37458SLiu Junliang 	.ndo_open		= usbnet_open,
307c9b37458SLiu Junliang 	.ndo_stop		= usbnet_stop,
308c9b37458SLiu Junliang 	.ndo_start_xmit		= usbnet_start_xmit,
309c9b37458SLiu Junliang 	.ndo_tx_timeout		= usbnet_tx_timeout,
310c9b37458SLiu Junliang 	.ndo_change_mtu		= usbnet_change_mtu,
311*323955a0SHeiner Kallweit 	.ndo_get_stats64	= dev_get_tstats64,
312c9b37458SLiu Junliang 	.ndo_validate_addr	= eth_validate_addr,
313c9b37458SLiu Junliang 	.ndo_do_ioctl		= sr9700_ioctl,
314c9b37458SLiu Junliang 	.ndo_set_rx_mode	= sr9700_set_multicast,
315c9b37458SLiu Junliang 	.ndo_set_mac_address	= sr9700_set_mac_address,
316c9b37458SLiu Junliang };
317c9b37458SLiu Junliang 
318c9b37458SLiu Junliang static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
319c9b37458SLiu Junliang {
320c9b37458SLiu Junliang 	struct net_device *netdev;
321c9b37458SLiu Junliang 	struct mii_if_info *mii;
322c9b37458SLiu Junliang 	int ret;
323c9b37458SLiu Junliang 
324c9b37458SLiu Junliang 	ret = usbnet_get_endpoints(dev, intf);
325c9b37458SLiu Junliang 	if (ret)
326c9b37458SLiu Junliang 		goto out;
327c9b37458SLiu Junliang 
328c9b37458SLiu Junliang 	netdev = dev->net;
329c9b37458SLiu Junliang 
330c9b37458SLiu Junliang 	netdev->netdev_ops = &sr9700_netdev_ops;
331c9b37458SLiu Junliang 	netdev->ethtool_ops = &sr9700_ethtool_ops;
332c9b37458SLiu Junliang 	netdev->hard_header_len += SR_TX_OVERHEAD;
333c9b37458SLiu Junliang 	dev->hard_mtu = netdev->mtu + netdev->hard_header_len;
334c9b37458SLiu Junliang 	/* bulkin buffer is preferably not less than 3K */
335c9b37458SLiu Junliang 	dev->rx_urb_size = 3072;
336c9b37458SLiu Junliang 
337c9b37458SLiu Junliang 	mii = &dev->mii;
338c9b37458SLiu Junliang 	mii->dev = netdev;
339c9b37458SLiu Junliang 	mii->mdio_read = sr_mdio_read;
340c9b37458SLiu Junliang 	mii->mdio_write = sr_mdio_write;
341c9b37458SLiu Junliang 	mii->phy_id_mask = 0x1f;
342c9b37458SLiu Junliang 	mii->reg_num_mask = 0x1f;
343c9b37458SLiu Junliang 
34406b19b1bSChen Gang 	sr_write_reg(dev, SR_NCR, NCR_RST);
345c9b37458SLiu Junliang 	udelay(20);
346c9b37458SLiu Junliang 
347c9b37458SLiu Junliang 	/* read MAC
348c9b37458SLiu Junliang 	 * After Chip Power on, the Chip will reload the MAC from
349c9b37458SLiu Junliang 	 * EEPROM automatically to PAR. In case there is no EEPROM externally,
350c9b37458SLiu Junliang 	 * a default MAC address is stored in PAR for making chip work properly.
351c9b37458SLiu Junliang 	 */
35206b19b1bSChen Gang 	if (sr_read(dev, SR_PAR, ETH_ALEN, netdev->dev_addr) < 0) {
353c9b37458SLiu Junliang 		netdev_err(netdev, "Error reading MAC address\n");
354c9b37458SLiu Junliang 		ret = -ENODEV;
355c9b37458SLiu Junliang 		goto out;
356c9b37458SLiu Junliang 	}
357c9b37458SLiu Junliang 
358c9b37458SLiu Junliang 	/* power up and reset phy */
35906b19b1bSChen Gang 	sr_write_reg(dev, SR_PRR, PRR_PHY_RST);
360c9b37458SLiu Junliang 	/* at least 10ms, here 20ms for safe */
361ba23dc64SJia-Ju Bai 	msleep(20);
36206b19b1bSChen Gang 	sr_write_reg(dev, SR_PRR, 0);
363c9b37458SLiu Junliang 	/* at least 1ms, here 2ms for reading right register */
364c9b37458SLiu Junliang 	udelay(2 * 1000);
365c9b37458SLiu Junliang 
366c9b37458SLiu Junliang 	/* receive broadcast packets */
367c9b37458SLiu Junliang 	sr9700_set_multicast(netdev);
368c9b37458SLiu Junliang 
369c9b37458SLiu Junliang 	sr_mdio_write(netdev, mii->phy_id, MII_BMCR, BMCR_RESET);
370c9b37458SLiu Junliang 	sr_mdio_write(netdev, mii->phy_id, MII_ADVERTISE, ADVERTISE_ALL |
371c9b37458SLiu Junliang 		      ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
372c9b37458SLiu Junliang 	mii_nway_restart(mii);
373c9b37458SLiu Junliang 
374c9b37458SLiu Junliang out:
375c9b37458SLiu Junliang 	return ret;
376c9b37458SLiu Junliang }
377c9b37458SLiu Junliang 
378c9b37458SLiu Junliang static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
379c9b37458SLiu Junliang {
380c9b37458SLiu Junliang 	struct sk_buff *sr_skb;
381c9b37458SLiu Junliang 	int len;
382c9b37458SLiu Junliang 
383c9b37458SLiu Junliang 	/* skb content (packets) format :
384c9b37458SLiu Junliang 	 *                    p0            p1            p2    ......    pm
385c9b37458SLiu Junliang 	 *                 /      \
386c9b37458SLiu Junliang 	 *            /                \
387c9b37458SLiu Junliang 	 *        /                            \
388c9b37458SLiu Junliang 	 *  /                                        \
389c9b37458SLiu Junliang 	 * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn
390c9b37458SLiu Junliang 	 *
391c9b37458SLiu Junliang 	 * p0 : packet 0
392c9b37458SLiu Junliang 	 * p0b0 : packet 0 byte 0
393c9b37458SLiu Junliang 	 *
394c9b37458SLiu Junliang 	 * b0: rx status
395c9b37458SLiu Junliang 	 * b1: packet length (incl crc) low
396c9b37458SLiu Junliang 	 * b2: packet length (incl crc) high
397c9b37458SLiu Junliang 	 * b3..n-4: packet data
398c9b37458SLiu Junliang 	 * bn-3..bn: ethernet packet crc
399c9b37458SLiu Junliang 	 */
400c9b37458SLiu Junliang 	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
401c9b37458SLiu Junliang 		netdev_err(dev->net, "unexpected tiny rx frame\n");
402c9b37458SLiu Junliang 		return 0;
403c9b37458SLiu Junliang 	}
404c9b37458SLiu Junliang 
405c9b37458SLiu Junliang 	/* one skb may contains multiple packets */
406c9b37458SLiu Junliang 	while (skb->len > SR_RX_OVERHEAD) {
407c9b37458SLiu Junliang 		if (skb->data[0] != 0x40)
408c9b37458SLiu Junliang 			return 0;
409c9b37458SLiu Junliang 
410c9b37458SLiu Junliang 		/* ignore the CRC length */
411c9b37458SLiu Junliang 		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
412c9b37458SLiu Junliang 
413c9b37458SLiu Junliang 		if (len > ETH_FRAME_LEN)
414c9b37458SLiu Junliang 			return 0;
415c9b37458SLiu Junliang 
416c9b37458SLiu Junliang 		/* the last packet of current skb */
417c9b37458SLiu Junliang 		if (skb->len == (len + SR_RX_OVERHEAD))	{
418c9b37458SLiu Junliang 			skb_pull(skb, 3);
419c9b37458SLiu Junliang 			skb->len = len;
420c9b37458SLiu Junliang 			skb_set_tail_pointer(skb, len);
421c9b37458SLiu Junliang 			skb->truesize = len + sizeof(struct sk_buff);
422c9b37458SLiu Junliang 			return 2;
423c9b37458SLiu Junliang 		}
424c9b37458SLiu Junliang 
425c9b37458SLiu Junliang 		/* skb_clone is used for address align */
426c9b37458SLiu Junliang 		sr_skb = skb_clone(skb, GFP_ATOMIC);
427c9b37458SLiu Junliang 		if (!sr_skb)
428c9b37458SLiu Junliang 			return 0;
429c9b37458SLiu Junliang 
430c9b37458SLiu Junliang 		sr_skb->len = len;
431c9b37458SLiu Junliang 		sr_skb->data = skb->data + 3;
432c9b37458SLiu Junliang 		skb_set_tail_pointer(sr_skb, len);
433c9b37458SLiu Junliang 		sr_skb->truesize = len + sizeof(struct sk_buff);
434c9b37458SLiu Junliang 		usbnet_skb_return(dev, sr_skb);
435c9b37458SLiu Junliang 
436c9b37458SLiu Junliang 		skb_pull(skb, len + SR_RX_OVERHEAD);
437f819cd92SYueHaibing 	}
438c9b37458SLiu Junliang 
439c9b37458SLiu Junliang 	return 0;
440c9b37458SLiu Junliang }
441c9b37458SLiu Junliang 
442c9b37458SLiu Junliang static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
443c9b37458SLiu Junliang 				       gfp_t flags)
444c9b37458SLiu Junliang {
445c9b37458SLiu Junliang 	int len;
446c9b37458SLiu Junliang 
447c9b37458SLiu Junliang 	/* SR9700 can only send out one ethernet packet at once.
448c9b37458SLiu Junliang 	 *
449c9b37458SLiu Junliang 	 * b0 b1 b2 b3 ...... b(n-4) b(n-3)...bn
450c9b37458SLiu Junliang 	 *
451c9b37458SLiu Junliang 	 * b0: rx status
452c9b37458SLiu Junliang 	 * b1: packet length (incl crc) low
453c9b37458SLiu Junliang 	 * b2: packet length (incl crc) high
454c9b37458SLiu Junliang 	 * b3..n-4: packet data
455c9b37458SLiu Junliang 	 * bn-3..bn: ethernet packet crc
456c9b37458SLiu Junliang 	 */
457c9b37458SLiu Junliang 
458c9b37458SLiu Junliang 	len = skb->len;
459c9b37458SLiu Junliang 
460d532c108SEric Dumazet 	if (skb_cow_head(skb, SR_TX_OVERHEAD)) {
461c9b37458SLiu Junliang 		dev_kfree_skb_any(skb);
462c9b37458SLiu Junliang 		return NULL;
463c9b37458SLiu Junliang 	}
464c9b37458SLiu Junliang 
465c9b37458SLiu Junliang 	__skb_push(skb, SR_TX_OVERHEAD);
466c9b37458SLiu Junliang 
467c9b37458SLiu Junliang 	/* usbnet adds padding if length is a multiple of packet size
468c9b37458SLiu Junliang 	 * if so, adjust length value in header
469c9b37458SLiu Junliang 	 */
470c9b37458SLiu Junliang 	if ((skb->len % dev->maxpacket) == 0)
471c9b37458SLiu Junliang 		len++;
472c9b37458SLiu Junliang 
473c9b37458SLiu Junliang 	skb->data[0] = len;
474c9b37458SLiu Junliang 	skb->data[1] = len >> 8;
475c9b37458SLiu Junliang 
476c9b37458SLiu Junliang 	return skb;
477c9b37458SLiu Junliang }
478c9b37458SLiu Junliang 
479c9b37458SLiu Junliang static void sr9700_status(struct usbnet *dev, struct urb *urb)
480c9b37458SLiu Junliang {
481c9b37458SLiu Junliang 	int link;
482c9b37458SLiu Junliang 	u8 *buf;
483c9b37458SLiu Junliang 
484c9b37458SLiu Junliang 	/* format:
485c9b37458SLiu Junliang 	   b0: net status
486c9b37458SLiu Junliang 	   b1: tx status 1
487c9b37458SLiu Junliang 	   b2: tx status 2
488c9b37458SLiu Junliang 	   b3: rx status
489c9b37458SLiu Junliang 	   b4: rx overflow
490c9b37458SLiu Junliang 	   b5: rx count
491c9b37458SLiu Junliang 	   b6: tx count
492c9b37458SLiu Junliang 	   b7: gpr
493c9b37458SLiu Junliang 	*/
494c9b37458SLiu Junliang 
495c9b37458SLiu Junliang 	if (urb->actual_length < 8)
496c9b37458SLiu Junliang 		return;
497c9b37458SLiu Junliang 
498c9b37458SLiu Junliang 	buf = urb->transfer_buffer;
499c9b37458SLiu Junliang 
500c9b37458SLiu Junliang 	link = !!(buf[0] & 0x40);
501c9b37458SLiu Junliang 	if (netif_carrier_ok(dev->net) != link) {
502c9b37458SLiu Junliang 		usbnet_link_change(dev, link, 1);
503c9b37458SLiu Junliang 		netdev_dbg(dev->net, "Link Status is: %d\n", link);
504c9b37458SLiu Junliang 	}
505c9b37458SLiu Junliang }
506c9b37458SLiu Junliang 
507c9b37458SLiu Junliang static int sr9700_link_reset(struct usbnet *dev)
508c9b37458SLiu Junliang {
509c9b37458SLiu Junliang 	struct ethtool_cmd ecmd;
510c9b37458SLiu Junliang 
511c9b37458SLiu Junliang 	mii_check_media(&dev->mii, 1, 1);
512c9b37458SLiu Junliang 	mii_ethtool_gset(&dev->mii, &ecmd);
513c9b37458SLiu Junliang 
514c9b37458SLiu Junliang 	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
515c9b37458SLiu Junliang 		   ecmd.speed, ecmd.duplex);
516c9b37458SLiu Junliang 
517c9b37458SLiu Junliang 	return 0;
518c9b37458SLiu Junliang }
519c9b37458SLiu Junliang 
520c9b37458SLiu Junliang static const struct driver_info sr9700_driver_info = {
521c9b37458SLiu Junliang 	.description	= "CoreChip SR9700 USB Ethernet",
522c9b37458SLiu Junliang 	.flags		= FLAG_ETHER,
523c9b37458SLiu Junliang 	.bind		= sr9700_bind,
524c9b37458SLiu Junliang 	.rx_fixup	= sr9700_rx_fixup,
525c9b37458SLiu Junliang 	.tx_fixup	= sr9700_tx_fixup,
526c9b37458SLiu Junliang 	.status		= sr9700_status,
527c9b37458SLiu Junliang 	.link_reset	= sr9700_link_reset,
528c9b37458SLiu Junliang 	.reset		= sr9700_link_reset,
529c9b37458SLiu Junliang };
530c9b37458SLiu Junliang 
531c9b37458SLiu Junliang static const struct usb_device_id products[] = {
532c9b37458SLiu Junliang 	{
533c9b37458SLiu Junliang 		USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
534c9b37458SLiu Junliang 		.driver_info = (unsigned long)&sr9700_driver_info,
535c9b37458SLiu Junliang 	},
536c9b37458SLiu Junliang 	{},			/* END */
537c9b37458SLiu Junliang };
538c9b37458SLiu Junliang 
539c9b37458SLiu Junliang MODULE_DEVICE_TABLE(usb, products);
540c9b37458SLiu Junliang 
541c9b37458SLiu Junliang static struct usb_driver sr9700_usb_driver = {
542c9b37458SLiu Junliang 	.name		= "sr9700",
543c9b37458SLiu Junliang 	.id_table	= products,
544c9b37458SLiu Junliang 	.probe		= usbnet_probe,
545c9b37458SLiu Junliang 	.disconnect	= usbnet_disconnect,
546c9b37458SLiu Junliang 	.suspend	= usbnet_suspend,
547c9b37458SLiu Junliang 	.resume		= usbnet_resume,
548c9b37458SLiu Junliang 	.disable_hub_initiated_lpm = 1,
549c9b37458SLiu Junliang };
550c9b37458SLiu Junliang 
551c9b37458SLiu Junliang module_usb_driver(sr9700_usb_driver);
552c9b37458SLiu Junliang 
553c9b37458SLiu Junliang MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
554c9b37458SLiu Junliang MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
555c9b37458SLiu Junliang MODULE_LICENSE("GPL");
556