xref: /openbmc/linux/drivers/net/usb/sr9700.c (revision 0db00e5d86dc793aab9722ad3728d99166eb7d96)
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 
sr_read(struct usbnet * dev,u8 reg,u16 length,void * data)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 
sr_write(struct usbnet * dev,u8 reg,u16 length,void * data)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 
sr_read_reg(struct usbnet * dev,u8 reg,u8 * value)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 
sr_write_reg(struct usbnet * dev,u8 reg,u8 value)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 
sr_write_async(struct usbnet * dev,u8 reg,u16 length,const void * data)5976660757SJakub Kicinski static void sr_write_async(struct usbnet *dev, u8 reg, u16 length,
6076660757SJakub 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 
sr_write_reg_async(struct usbnet * dev,u8 reg,u8 value)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 
wait_phy_eeprom_ready(struct usbnet * dev,int phy)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 
sr_share_read_word(struct usbnet * dev,int phy,u8 reg,__le16 * value)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 
sr_share_write_word(struct usbnet * dev,int phy,u8 reg,__le16 value)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 
sr_read_eeprom_word(struct usbnet * dev,u8 offset,void * value)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 
sr9700_get_eeprom_len(struct net_device * netdev)151c9b37458SLiu Junliang static int sr9700_get_eeprom_len(struct net_device *netdev)
152c9b37458SLiu Junliang {
153c9b37458SLiu Junliang 	return SR_EEPROM_LEN;
154c9b37458SLiu Junliang }
155c9b37458SLiu Junliang 
sr9700_get_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * data)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 
sr_mdio_read(struct net_device * netdev,int phy_id,int loc)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;
182*f2b5be33SMa Ke 	int err;
183c9b37458SLiu Junliang 
184c9b37458SLiu Junliang 	if (phy_id) {
185c9b37458SLiu Junliang 		netdev_dbg(netdev, "Only internal phy supported\n");
186c9b37458SLiu Junliang 		return 0;
187c9b37458SLiu Junliang 	}
188c9b37458SLiu Junliang 
189c9b37458SLiu Junliang 	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
190c9b37458SLiu Junliang 	if (loc == MII_BMSR) {
191c9b37458SLiu Junliang 		u8 value;
192c9b37458SLiu Junliang 
193*f2b5be33SMa Ke 		err = sr_read_reg(dev, SR_NSR, &value);
194*f2b5be33SMa Ke 		if (err < 0)
195*f2b5be33SMa Ke 			return err;
196*f2b5be33SMa Ke 
197c9b37458SLiu Junliang 		if (value & NSR_LINKST)
198c9b37458SLiu Junliang 			rc = 1;
199c9b37458SLiu Junliang 	}
200*f2b5be33SMa Ke 	err = sr_share_read_word(dev, 1, loc, &res);
201*f2b5be33SMa Ke 	if (err < 0)
202*f2b5be33SMa Ke 		return err;
203*f2b5be33SMa Ke 
204c9b37458SLiu Junliang 	if (rc == 1)
205c9b37458SLiu Junliang 		res = le16_to_cpu(res) | BMSR_LSTATUS;
206c9b37458SLiu Junliang 	else
207c9b37458SLiu Junliang 		res = le16_to_cpu(res) & ~BMSR_LSTATUS;
208c9b37458SLiu Junliang 
209c9b37458SLiu Junliang 	netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
210c9b37458SLiu Junliang 		   phy_id, loc, res);
211c9b37458SLiu Junliang 
212c9b37458SLiu Junliang 	return res;
213c9b37458SLiu Junliang }
214c9b37458SLiu Junliang 
sr_mdio_write(struct net_device * netdev,int phy_id,int loc,int val)215c9b37458SLiu Junliang static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc,
216c9b37458SLiu Junliang 			  int val)
217c9b37458SLiu Junliang {
218c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
219c9b37458SLiu Junliang 	__le16 res = cpu_to_le16(val);
220c9b37458SLiu Junliang 
221c9b37458SLiu Junliang 	if (phy_id) {
222c9b37458SLiu Junliang 		netdev_dbg(netdev, "Only internal phy supported\n");
223c9b37458SLiu Junliang 		return;
224c9b37458SLiu Junliang 	}
225c9b37458SLiu Junliang 
226c9b37458SLiu Junliang 	netdev_dbg(netdev, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
227c9b37458SLiu Junliang 		   phy_id, loc, val);
228c9b37458SLiu Junliang 
229c9b37458SLiu Junliang 	sr_share_write_word(dev, 1, loc, res);
230c9b37458SLiu Junliang }
231c9b37458SLiu Junliang 
sr9700_get_link(struct net_device * netdev)232c9b37458SLiu Junliang static u32 sr9700_get_link(struct net_device *netdev)
233c9b37458SLiu Junliang {
234c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
235c9b37458SLiu Junliang 	u8 value = 0;
236c9b37458SLiu Junliang 	int rc = 0;
237c9b37458SLiu Junliang 
238c9b37458SLiu Junliang 	/* Get the Link Status directly */
23906b19b1bSChen Gang 	sr_read_reg(dev, SR_NSR, &value);
240c9b37458SLiu Junliang 	if (value & NSR_LINKST)
241c9b37458SLiu Junliang 		rc = 1;
242c9b37458SLiu Junliang 
243c9b37458SLiu Junliang 	return rc;
244c9b37458SLiu Junliang }
245c9b37458SLiu Junliang 
sr9700_ioctl(struct net_device * netdev,struct ifreq * rq,int cmd)246c9b37458SLiu Junliang static int sr9700_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
247c9b37458SLiu Junliang {
248c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
249c9b37458SLiu Junliang 
250c9b37458SLiu Junliang 	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
251c9b37458SLiu Junliang }
252c9b37458SLiu Junliang 
253c9b37458SLiu Junliang static const struct ethtool_ops sr9700_ethtool_ops = {
254c9b37458SLiu Junliang 	.get_drvinfo	= usbnet_get_drvinfo,
255c9b37458SLiu Junliang 	.get_link	= sr9700_get_link,
256c9b37458SLiu Junliang 	.get_msglevel	= usbnet_get_msglevel,
257c9b37458SLiu Junliang 	.set_msglevel	= usbnet_set_msglevel,
258c9b37458SLiu Junliang 	.get_eeprom_len	= sr9700_get_eeprom_len,
259c9b37458SLiu Junliang 	.get_eeprom	= sr9700_get_eeprom,
260c9b37458SLiu Junliang 	.nway_reset	= usbnet_nway_reset,
26177651900SOliver Neukum 	.get_link_ksettings	= usbnet_get_link_ksettings_mii,
26277651900SOliver Neukum 	.set_link_ksettings	= usbnet_set_link_ksettings_mii,
263c9b37458SLiu Junliang };
264c9b37458SLiu Junliang 
sr9700_set_multicast(struct net_device * netdev)265c9b37458SLiu Junliang static void sr9700_set_multicast(struct net_device *netdev)
266c9b37458SLiu Junliang {
267c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
268c9b37458SLiu Junliang 	/* We use the 20 byte dev->data for our 8 byte filter buffer
269c9b37458SLiu Junliang 	 * to avoid allocating memory that is tricky to free later
270c9b37458SLiu Junliang 	 */
271c9b37458SLiu Junliang 	u8 *hashes = (u8 *)&dev->data;
272c9b37458SLiu Junliang 	/* rx_ctl setting : enable, disable_long, disable_crc */
273c9b37458SLiu Junliang 	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
274c9b37458SLiu Junliang 
275c9b37458SLiu Junliang 	memset(hashes, 0x00, SR_MCAST_SIZE);
276c9b37458SLiu Junliang 	/* broadcast address */
277c9b37458SLiu Junliang 	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;
278c9b37458SLiu Junliang 	if (netdev->flags & IFF_PROMISC) {
279c9b37458SLiu Junliang 		rx_ctl |= RCR_PRMSC;
280c9b37458SLiu Junliang 	} else if (netdev->flags & IFF_ALLMULTI ||
281c9b37458SLiu Junliang 		   netdev_mc_count(netdev) > SR_MCAST_MAX) {
282c9b37458SLiu Junliang 		rx_ctl |= RCR_RUNT;
283c9b37458SLiu Junliang 	} else if (!netdev_mc_empty(netdev)) {
284c9b37458SLiu Junliang 		struct netdev_hw_addr *ha;
285c9b37458SLiu Junliang 
286c9b37458SLiu Junliang 		netdev_for_each_mc_addr(ha, netdev) {
287c9b37458SLiu Junliang 			u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
288c9b37458SLiu Junliang 			hashes[crc >> 3] |= 1 << (crc & 0x7);
289c9b37458SLiu Junliang 		}
290c9b37458SLiu Junliang 	}
291c9b37458SLiu Junliang 
29206b19b1bSChen Gang 	sr_write_async(dev, SR_MAR, SR_MCAST_SIZE, hashes);
29306b19b1bSChen Gang 	sr_write_reg_async(dev, SR_RCR, rx_ctl);
294c9b37458SLiu Junliang }
295c9b37458SLiu Junliang 
sr9700_set_mac_address(struct net_device * netdev,void * p)296c9b37458SLiu Junliang static int sr9700_set_mac_address(struct net_device *netdev, void *p)
297c9b37458SLiu Junliang {
298c9b37458SLiu Junliang 	struct usbnet *dev = netdev_priv(netdev);
299c9b37458SLiu Junliang 	struct sockaddr *addr = p;
300c9b37458SLiu Junliang 
301c9b37458SLiu Junliang 	if (!is_valid_ether_addr(addr->sa_data)) {
302c9b37458SLiu Junliang 		netdev_err(netdev, "not setting invalid mac address %pM\n",
303c9b37458SLiu Junliang 			   addr->sa_data);
304c9b37458SLiu Junliang 		return -EINVAL;
305c9b37458SLiu Junliang 	}
306c9b37458SLiu Junliang 
30749ed8ddeSJakub Kicinski 	eth_hw_addr_set(netdev, addr->sa_data);
30806b19b1bSChen Gang 	sr_write_async(dev, SR_PAR, 6, netdev->dev_addr);
309c9b37458SLiu Junliang 
310c9b37458SLiu Junliang 	return 0;
311c9b37458SLiu Junliang }
312c9b37458SLiu Junliang 
313c9b37458SLiu Junliang static const struct net_device_ops sr9700_netdev_ops = {
314c9b37458SLiu Junliang 	.ndo_open		= usbnet_open,
315c9b37458SLiu Junliang 	.ndo_stop		= usbnet_stop,
316c9b37458SLiu Junliang 	.ndo_start_xmit		= usbnet_start_xmit,
317c9b37458SLiu Junliang 	.ndo_tx_timeout		= usbnet_tx_timeout,
318c9b37458SLiu Junliang 	.ndo_change_mtu		= usbnet_change_mtu,
319323955a0SHeiner Kallweit 	.ndo_get_stats64	= dev_get_tstats64,
320c9b37458SLiu Junliang 	.ndo_validate_addr	= eth_validate_addr,
321a7605370SArnd Bergmann 	.ndo_eth_ioctl		= sr9700_ioctl,
322c9b37458SLiu Junliang 	.ndo_set_rx_mode	= sr9700_set_multicast,
323c9b37458SLiu Junliang 	.ndo_set_mac_address	= sr9700_set_mac_address,
324c9b37458SLiu Junliang };
325c9b37458SLiu Junliang 
sr9700_bind(struct usbnet * dev,struct usb_interface * intf)326c9b37458SLiu Junliang static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
327c9b37458SLiu Junliang {
328c9b37458SLiu Junliang 	struct net_device *netdev;
329c9b37458SLiu Junliang 	struct mii_if_info *mii;
3302674e7eaSJakub Kicinski 	u8 addr[ETH_ALEN];
331c9b37458SLiu Junliang 	int ret;
332c9b37458SLiu Junliang 
333c9b37458SLiu Junliang 	ret = usbnet_get_endpoints(dev, intf);
334c9b37458SLiu Junliang 	if (ret)
335c9b37458SLiu Junliang 		goto out;
336c9b37458SLiu Junliang 
337c9b37458SLiu Junliang 	netdev = dev->net;
338c9b37458SLiu Junliang 
339c9b37458SLiu Junliang 	netdev->netdev_ops = &sr9700_netdev_ops;
340c9b37458SLiu Junliang 	netdev->ethtool_ops = &sr9700_ethtool_ops;
341c9b37458SLiu Junliang 	netdev->hard_header_len += SR_TX_OVERHEAD;
342c9b37458SLiu Junliang 	dev->hard_mtu = netdev->mtu + netdev->hard_header_len;
343c9b37458SLiu Junliang 	/* bulkin buffer is preferably not less than 3K */
344c9b37458SLiu Junliang 	dev->rx_urb_size = 3072;
345c9b37458SLiu Junliang 
346c9b37458SLiu Junliang 	mii = &dev->mii;
347c9b37458SLiu Junliang 	mii->dev = netdev;
348c9b37458SLiu Junliang 	mii->mdio_read = sr_mdio_read;
349c9b37458SLiu Junliang 	mii->mdio_write = sr_mdio_write;
350c9b37458SLiu Junliang 	mii->phy_id_mask = 0x1f;
351c9b37458SLiu Junliang 	mii->reg_num_mask = 0x1f;
352c9b37458SLiu Junliang 
35306b19b1bSChen Gang 	sr_write_reg(dev, SR_NCR, NCR_RST);
354c9b37458SLiu Junliang 	udelay(20);
355c9b37458SLiu Junliang 
356c9b37458SLiu Junliang 	/* read MAC
357c9b37458SLiu Junliang 	 * After Chip Power on, the Chip will reload the MAC from
358c9b37458SLiu Junliang 	 * EEPROM automatically to PAR. In case there is no EEPROM externally,
359c9b37458SLiu Junliang 	 * a default MAC address is stored in PAR for making chip work properly.
360c9b37458SLiu Junliang 	 */
3612674e7eaSJakub Kicinski 	if (sr_read(dev, SR_PAR, ETH_ALEN, addr) < 0) {
362c9b37458SLiu Junliang 		netdev_err(netdev, "Error reading MAC address\n");
363c9b37458SLiu Junliang 		ret = -ENODEV;
364c9b37458SLiu Junliang 		goto out;
365c9b37458SLiu Junliang 	}
3662674e7eaSJakub Kicinski 	eth_hw_addr_set(netdev, addr);
367c9b37458SLiu Junliang 
368c9b37458SLiu Junliang 	/* power up and reset phy */
36906b19b1bSChen Gang 	sr_write_reg(dev, SR_PRR, PRR_PHY_RST);
370c9b37458SLiu Junliang 	/* at least 10ms, here 20ms for safe */
371ba23dc64SJia-Ju Bai 	msleep(20);
37206b19b1bSChen Gang 	sr_write_reg(dev, SR_PRR, 0);
373c9b37458SLiu Junliang 	/* at least 1ms, here 2ms for reading right register */
374c9b37458SLiu Junliang 	udelay(2 * 1000);
375c9b37458SLiu Junliang 
376c9b37458SLiu Junliang 	/* receive broadcast packets */
377c9b37458SLiu Junliang 	sr9700_set_multicast(netdev);
378c9b37458SLiu Junliang 
379c9b37458SLiu Junliang 	sr_mdio_write(netdev, mii->phy_id, MII_BMCR, BMCR_RESET);
380c9b37458SLiu Junliang 	sr_mdio_write(netdev, mii->phy_id, MII_ADVERTISE, ADVERTISE_ALL |
381c9b37458SLiu Junliang 		      ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
382c9b37458SLiu Junliang 	mii_nway_restart(mii);
383c9b37458SLiu Junliang 
384c9b37458SLiu Junliang out:
385c9b37458SLiu Junliang 	return ret;
386c9b37458SLiu Junliang }
387c9b37458SLiu Junliang 
sr9700_rx_fixup(struct usbnet * dev,struct sk_buff * skb)388c9b37458SLiu Junliang static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
389c9b37458SLiu Junliang {
390c9b37458SLiu Junliang 	struct sk_buff *sr_skb;
391c9b37458SLiu Junliang 	int len;
392c9b37458SLiu Junliang 
393c9b37458SLiu Junliang 	/* skb content (packets) format :
394c9b37458SLiu Junliang 	 *                    p0            p1            p2    ......    pm
395c9b37458SLiu Junliang 	 *                 /      \
396c9b37458SLiu Junliang 	 *            /                \
397c9b37458SLiu Junliang 	 *        /                            \
398c9b37458SLiu Junliang 	 *  /                                        \
399c9b37458SLiu Junliang 	 * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn
400c9b37458SLiu Junliang 	 *
401c9b37458SLiu Junliang 	 * p0 : packet 0
402c9b37458SLiu Junliang 	 * p0b0 : packet 0 byte 0
403c9b37458SLiu Junliang 	 *
404c9b37458SLiu Junliang 	 * b0: rx status
405c9b37458SLiu Junliang 	 * b1: packet length (incl crc) low
406c9b37458SLiu Junliang 	 * b2: packet length (incl crc) high
407c9b37458SLiu Junliang 	 * b3..n-4: packet data
408c9b37458SLiu Junliang 	 * bn-3..bn: ethernet packet crc
409c9b37458SLiu Junliang 	 */
410c9b37458SLiu Junliang 	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
411c9b37458SLiu Junliang 		netdev_err(dev->net, "unexpected tiny rx frame\n");
412c9b37458SLiu Junliang 		return 0;
413c9b37458SLiu Junliang 	}
414c9b37458SLiu Junliang 
415c9b37458SLiu Junliang 	/* one skb may contains multiple packets */
416c9b37458SLiu Junliang 	while (skb->len > SR_RX_OVERHEAD) {
417c9b37458SLiu Junliang 		if (skb->data[0] != 0x40)
418c9b37458SLiu Junliang 			return 0;
419c9b37458SLiu Junliang 
420c9b37458SLiu Junliang 		/* ignore the CRC length */
421c9b37458SLiu Junliang 		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
422c9b37458SLiu Junliang 
423ecf7cf8eSSzymon Heidrich 		if (len > ETH_FRAME_LEN || len > skb->len || len < 0)
424c9b37458SLiu Junliang 			return 0;
425c9b37458SLiu Junliang 
426c9b37458SLiu Junliang 		/* the last packet of current skb */
427c9b37458SLiu Junliang 		if (skb->len == (len + SR_RX_OVERHEAD))	{
428c9b37458SLiu Junliang 			skb_pull(skb, 3);
429c9b37458SLiu Junliang 			skb->len = len;
430c9b37458SLiu Junliang 			skb_set_tail_pointer(skb, len);
431c9b37458SLiu Junliang 			return 2;
432c9b37458SLiu Junliang 		}
433c9b37458SLiu Junliang 
434979d764eSEric Dumazet 		sr_skb = netdev_alloc_skb_ip_align(dev->net, len);
435c9b37458SLiu Junliang 		if (!sr_skb)
436c9b37458SLiu Junliang 			return 0;
437c9b37458SLiu Junliang 
438979d764eSEric Dumazet 		skb_put(sr_skb, len);
439979d764eSEric Dumazet 		memcpy(sr_skb->data, skb->data + 3, len);
440c9b37458SLiu Junliang 		usbnet_skb_return(dev, sr_skb);
441c9b37458SLiu Junliang 
442c9b37458SLiu Junliang 		skb_pull(skb, len + SR_RX_OVERHEAD);
443f819cd92SYueHaibing 	}
444c9b37458SLiu Junliang 
445c9b37458SLiu Junliang 	return 0;
446c9b37458SLiu Junliang }
447c9b37458SLiu Junliang 
sr9700_tx_fixup(struct usbnet * dev,struct sk_buff * skb,gfp_t flags)448c9b37458SLiu Junliang static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
449c9b37458SLiu Junliang 				       gfp_t flags)
450c9b37458SLiu Junliang {
451c9b37458SLiu Junliang 	int len;
452c9b37458SLiu Junliang 
453c9b37458SLiu Junliang 	/* SR9700 can only send out one ethernet packet at once.
454c9b37458SLiu Junliang 	 *
455c9b37458SLiu Junliang 	 * b0 b1 b2 b3 ...... b(n-4) b(n-3)...bn
456c9b37458SLiu Junliang 	 *
457c9b37458SLiu Junliang 	 * b0: rx status
458c9b37458SLiu Junliang 	 * b1: packet length (incl crc) low
459c9b37458SLiu Junliang 	 * b2: packet length (incl crc) high
460c9b37458SLiu Junliang 	 * b3..n-4: packet data
461c9b37458SLiu Junliang 	 * bn-3..bn: ethernet packet crc
462c9b37458SLiu Junliang 	 */
463c9b37458SLiu Junliang 
464c9b37458SLiu Junliang 	len = skb->len;
465c9b37458SLiu Junliang 
466d532c108SEric Dumazet 	if (skb_cow_head(skb, SR_TX_OVERHEAD)) {
467c9b37458SLiu Junliang 		dev_kfree_skb_any(skb);
468c9b37458SLiu Junliang 		return NULL;
469c9b37458SLiu Junliang 	}
470c9b37458SLiu Junliang 
471c9b37458SLiu Junliang 	__skb_push(skb, SR_TX_OVERHEAD);
472c9b37458SLiu Junliang 
473c9b37458SLiu Junliang 	/* usbnet adds padding if length is a multiple of packet size
474c9b37458SLiu Junliang 	 * if so, adjust length value in header
475c9b37458SLiu Junliang 	 */
476c9b37458SLiu Junliang 	if ((skb->len % dev->maxpacket) == 0)
477c9b37458SLiu Junliang 		len++;
478c9b37458SLiu Junliang 
479c9b37458SLiu Junliang 	skb->data[0] = len;
480c9b37458SLiu Junliang 	skb->data[1] = len >> 8;
481c9b37458SLiu Junliang 
482c9b37458SLiu Junliang 	return skb;
483c9b37458SLiu Junliang }
484c9b37458SLiu Junliang 
sr9700_status(struct usbnet * dev,struct urb * urb)485c9b37458SLiu Junliang static void sr9700_status(struct usbnet *dev, struct urb *urb)
486c9b37458SLiu Junliang {
487c9b37458SLiu Junliang 	int link;
488c9b37458SLiu Junliang 	u8 *buf;
489c9b37458SLiu Junliang 
490c9b37458SLiu Junliang 	/* format:
491c9b37458SLiu Junliang 	   b0: net status
492c9b37458SLiu Junliang 	   b1: tx status 1
493c9b37458SLiu Junliang 	   b2: tx status 2
494c9b37458SLiu Junliang 	   b3: rx status
495c9b37458SLiu Junliang 	   b4: rx overflow
496c9b37458SLiu Junliang 	   b5: rx count
497c9b37458SLiu Junliang 	   b6: tx count
498c9b37458SLiu Junliang 	   b7: gpr
499c9b37458SLiu Junliang 	*/
500c9b37458SLiu Junliang 
501c9b37458SLiu Junliang 	if (urb->actual_length < 8)
502c9b37458SLiu Junliang 		return;
503c9b37458SLiu Junliang 
504c9b37458SLiu Junliang 	buf = urb->transfer_buffer;
505c9b37458SLiu Junliang 
506c9b37458SLiu Junliang 	link = !!(buf[0] & 0x40);
507c9b37458SLiu Junliang 	if (netif_carrier_ok(dev->net) != link) {
508c9b37458SLiu Junliang 		usbnet_link_change(dev, link, 1);
509c9b37458SLiu Junliang 		netdev_dbg(dev->net, "Link Status is: %d\n", link);
510c9b37458SLiu Junliang 	}
511c9b37458SLiu Junliang }
512c9b37458SLiu Junliang 
sr9700_link_reset(struct usbnet * dev)513c9b37458SLiu Junliang static int sr9700_link_reset(struct usbnet *dev)
514c9b37458SLiu Junliang {
515c9b37458SLiu Junliang 	struct ethtool_cmd ecmd;
516c9b37458SLiu Junliang 
517c9b37458SLiu Junliang 	mii_check_media(&dev->mii, 1, 1);
518c9b37458SLiu Junliang 	mii_ethtool_gset(&dev->mii, &ecmd);
519c9b37458SLiu Junliang 
520c9b37458SLiu Junliang 	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
521c9b37458SLiu Junliang 		   ecmd.speed, ecmd.duplex);
522c9b37458SLiu Junliang 
523c9b37458SLiu Junliang 	return 0;
524c9b37458SLiu Junliang }
525c9b37458SLiu Junliang 
526c9b37458SLiu Junliang static const struct driver_info sr9700_driver_info = {
527c9b37458SLiu Junliang 	.description	= "CoreChip SR9700 USB Ethernet",
528c9b37458SLiu Junliang 	.flags		= FLAG_ETHER,
529c9b37458SLiu Junliang 	.bind		= sr9700_bind,
530c9b37458SLiu Junliang 	.rx_fixup	= sr9700_rx_fixup,
531c9b37458SLiu Junliang 	.tx_fixup	= sr9700_tx_fixup,
532c9b37458SLiu Junliang 	.status		= sr9700_status,
533c9b37458SLiu Junliang 	.link_reset	= sr9700_link_reset,
534c9b37458SLiu Junliang 	.reset		= sr9700_link_reset,
535c9b37458SLiu Junliang };
536c9b37458SLiu Junliang 
537c9b37458SLiu Junliang static const struct usb_device_id products[] = {
538c9b37458SLiu Junliang 	{
539c9b37458SLiu Junliang 		USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
540c9b37458SLiu Junliang 		.driver_info = (unsigned long)&sr9700_driver_info,
541c9b37458SLiu Junliang 	},
542c9b37458SLiu Junliang 	{},			/* END */
543c9b37458SLiu Junliang };
544c9b37458SLiu Junliang 
545c9b37458SLiu Junliang MODULE_DEVICE_TABLE(usb, products);
546c9b37458SLiu Junliang 
547c9b37458SLiu Junliang static struct usb_driver sr9700_usb_driver = {
548c9b37458SLiu Junliang 	.name		= "sr9700",
549c9b37458SLiu Junliang 	.id_table	= products,
550c9b37458SLiu Junliang 	.probe		= usbnet_probe,
551c9b37458SLiu Junliang 	.disconnect	= usbnet_disconnect,
552c9b37458SLiu Junliang 	.suspend	= usbnet_suspend,
553c9b37458SLiu Junliang 	.resume		= usbnet_resume,
554c9b37458SLiu Junliang 	.disable_hub_initiated_lpm = 1,
555c9b37458SLiu Junliang };
556c9b37458SLiu Junliang 
557c9b37458SLiu Junliang module_usb_driver(sr9700_usb_driver);
558c9b37458SLiu Junliang 
559c9b37458SLiu Junliang MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
560c9b37458SLiu Junliang MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
561c9b37458SLiu Junliang MODULE_LICENSE("GPL");
562