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