File Index
Files and directories
Sign in
FILE

sr9700.c

File preview with syntax highlighting.

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