1 /*
2  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <string.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <byteswap.h>
30 #include <ipxe/ethernet.h>
31 #include <ipxe/usb.h>
32 #include <ipxe/usbnet.h>
33 #include <ipxe/profile.h>
34 #include "smsc75xx.h"
35 
36 /** @file
37  *
38  * SMSC LAN75xx USB Ethernet driver
39  *
40  */
41 
42 /** Bulk IN completion profiler */
43 static struct profiler smsc75xx_in_profiler __profiler =
44 	{ .name = "smsc75xx.in" };
45 
46 /** Bulk OUT profiler */
47 static struct profiler smsc75xx_out_profiler __profiler =
48 	{ .name = "smsc75xx.out" };
49 
50 /******************************************************************************
51  *
52  * Statistics (for debugging)
53  *
54  ******************************************************************************
55  */
56 
57 /**
58  * Dump statistics (for debugging)
59  *
60  * @v smscusb		SMSC USB device
61  * @ret rc		Return status code
62  */
smsc75xx_dump_statistics(struct smscusb_device * smscusb)63 int smsc75xx_dump_statistics ( struct smscusb_device *smscusb ) {
64 	struct smsc75xx_statistics stats;
65 	int rc;
66 
67 	/* Do nothing unless debugging is enabled */
68 	if ( ! DBG_LOG )
69 		return 0;
70 
71 	/* Get statistics */
72 	if ( ( rc = smscusb_get_statistics ( smscusb, 0, &stats,
73 					     sizeof ( stats ) ) ) != 0 ) {
74 		DBGC ( smscusb, "SMSC75XX %p could not get statistics: "
75 		       "%s\n", smscusb, strerror ( rc ) );
76 		return rc;
77 	}
78 
79 	/* Dump statistics */
80 	DBGC ( smscusb, "SMSC75XX %p RXE fcs %d aln %d frg %d jab %d und %d "
81 	       "ovr %d drp %d\n", smscusb, le32_to_cpu ( stats.rx.err.fcs ),
82 	       le32_to_cpu ( stats.rx.err.alignment ),
83 	       le32_to_cpu ( stats.rx.err.fragment ),
84 	       le32_to_cpu ( stats.rx.err.jabber ),
85 	       le32_to_cpu ( stats.rx.err.undersize ),
86 	       le32_to_cpu ( stats.rx.err.oversize ),
87 	       le32_to_cpu ( stats.rx.err.dropped ) );
88 	DBGC ( smscusb, "SMSC75XX %p RXB ucast %d bcast %d mcast %d\n",
89 	       smscusb, le32_to_cpu ( stats.rx.byte.unicast ),
90 	       le32_to_cpu ( stats.rx.byte.broadcast ),
91 	       le32_to_cpu ( stats.rx.byte.multicast ) );
92 	DBGC ( smscusb, "SMSC75XX %p RXF ucast %d bcast %d mcast %d pause "
93 	       "%d\n", smscusb, le32_to_cpu ( stats.rx.frame.unicast ),
94 	       le32_to_cpu ( stats.rx.frame.broadcast ),
95 	       le32_to_cpu ( stats.rx.frame.multicast ),
96 	       le32_to_cpu ( stats.rx.frame.pause ) );
97 	DBGC ( smscusb, "SMSC75XX %p TXE fcs %d def %d car %d cnt %d sgl %d "
98 	       "mul %d exc %d lat %d\n", smscusb,
99 	       le32_to_cpu ( stats.tx.err.fcs ),
100 	       le32_to_cpu ( stats.tx.err.deferral ),
101 	       le32_to_cpu ( stats.tx.err.carrier ),
102 	       le32_to_cpu ( stats.tx.err.count ),
103 	       le32_to_cpu ( stats.tx.err.single ),
104 	       le32_to_cpu ( stats.tx.err.multiple ),
105 	       le32_to_cpu ( stats.tx.err.excessive ),
106 	       le32_to_cpu ( stats.tx.err.late ) );
107 	DBGC ( smscusb, "SMSC75XX %p TXB ucast %d bcast %d mcast %d\n",
108 	       smscusb, le32_to_cpu ( stats.tx.byte.unicast ),
109 	       le32_to_cpu ( stats.tx.byte.broadcast ),
110 	       le32_to_cpu ( stats.tx.byte.multicast ) );
111 	DBGC ( smscusb, "SMSC75XX %p TXF ucast %d bcast %d mcast %d pause "
112 	       "%d\n", smscusb, le32_to_cpu ( stats.tx.frame.unicast ),
113 	       le32_to_cpu ( stats.tx.frame.broadcast ),
114 	       le32_to_cpu ( stats.tx.frame.multicast ),
115 	       le32_to_cpu ( stats.tx.frame.pause ) );
116 
117 	return 0;
118 }
119 
120 /******************************************************************************
121  *
122  * Device reset
123  *
124  ******************************************************************************
125  */
126 
127 /**
128  * Reset device
129  *
130  * @v smscusb		SMSC USB device
131  * @ret rc		Return status code
132  */
smsc75xx_reset(struct smscusb_device * smscusb)133 static int smsc75xx_reset ( struct smscusb_device *smscusb ) {
134 	uint32_t hw_cfg;
135 	unsigned int i;
136 	int rc;
137 
138 	/* Reset device */
139 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_HW_CFG,
140 				     SMSC75XX_HW_CFG_LRST ) ) != 0 )
141 		return rc;
142 
143 	/* Wait for reset to complete */
144 	for ( i = 0 ; i < SMSC75XX_RESET_MAX_WAIT_MS ; i++ ) {
145 
146 		/* Check if reset has completed */
147 		if ( ( rc = smscusb_readl ( smscusb, SMSC75XX_HW_CFG,
148 					    &hw_cfg ) ) != 0 )
149 			return rc;
150 		if ( ! ( hw_cfg & SMSC75XX_HW_CFG_LRST ) )
151 			return 0;
152 
153 		/* Delay */
154 		mdelay ( 1 );
155 	}
156 
157 	DBGC ( smscusb, "SMSC75XX %p timed out waiting for reset\n",
158 	       smscusb );
159 	return -ETIMEDOUT;
160 }
161 
162 /******************************************************************************
163  *
164  * Endpoint operations
165  *
166  ******************************************************************************
167  */
168 
169 /**
170  * Complete bulk IN transfer
171  *
172  * @v ep		USB endpoint
173  * @v iobuf		I/O buffer
174  * @v rc		Completion status code
175  */
smsc75xx_in_complete(struct usb_endpoint * ep,struct io_buffer * iobuf,int rc)176 static void smsc75xx_in_complete ( struct usb_endpoint *ep,
177 				   struct io_buffer *iobuf, int rc ) {
178 	struct smscusb_device *smscusb =
179 		container_of ( ep, struct smscusb_device, usbnet.in );
180 	struct net_device *netdev = smscusb->netdev;
181 	struct smsc75xx_rx_header *header;
182 
183 	/* Profile completions */
184 	profile_start ( &smsc75xx_in_profiler );
185 
186 	/* Ignore packets cancelled when the endpoint closes */
187 	if ( ! ep->open ) {
188 		free_iob ( iobuf );
189 		return;
190 	}
191 
192 	/* Record USB errors against the network device */
193 	if ( rc != 0 ) {
194 		DBGC ( smscusb, "SMSC75XX %p bulk IN failed: %s\n",
195 		       smscusb, strerror ( rc ) );
196 		goto err;
197 	}
198 
199 	/* Sanity check */
200 	if ( iob_len ( iobuf ) < ( sizeof ( *header ) ) ) {
201 		DBGC ( smscusb, "SMSC75XX %p underlength bulk IN\n",
202 		       smscusb );
203 		DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
204 		rc = -EINVAL;
205 		goto err;
206 	}
207 
208 	/* Strip header */
209 	header = iobuf->data;
210 	iob_pull ( iobuf, sizeof ( *header ) );
211 
212 	/* Check for errors */
213 	if ( header->command & cpu_to_le32 ( SMSC75XX_RX_RED ) ) {
214 		DBGC ( smscusb, "SMSC75XX %p receive error (%08x):\n",
215 		       smscusb, le32_to_cpu ( header->command ) );
216 		DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
217 		rc = -EIO;
218 		goto err;
219 	}
220 
221 	/* Hand off to network stack */
222 	netdev_rx ( netdev, iob_disown ( iobuf ) );
223 
224 	profile_stop ( &smsc75xx_in_profiler );
225 	return;
226 
227  err:
228 	/* Hand off to network stack */
229 	netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
230 }
231 
232 /** Bulk IN endpoint operations */
233 struct usb_endpoint_driver_operations smsc75xx_in_operations = {
234 	.complete = smsc75xx_in_complete,
235 };
236 
237 /**
238  * Transmit packet
239  *
240  * @v smscusb		SMSC USB device
241  * @v iobuf		I/O buffer
242  * @ret rc		Return status code
243  */
smsc75xx_out_transmit(struct smscusb_device * smscusb,struct io_buffer * iobuf)244 static int smsc75xx_out_transmit ( struct smscusb_device *smscusb,
245 				   struct io_buffer *iobuf ) {
246 	struct smsc75xx_tx_header *header;
247 	size_t len = iob_len ( iobuf );
248 	int rc;
249 
250 	/* Profile transmissions */
251 	profile_start ( &smsc75xx_out_profiler );
252 
253 	/* Prepend header */
254 	if ( ( rc = iob_ensure_headroom ( iobuf, sizeof ( *header ) ) ) != 0 )
255 		return rc;
256 	header = iob_push ( iobuf, sizeof ( *header ) );
257 	header->command = cpu_to_le32 ( SMSC75XX_TX_FCS | len );
258 	header->tag = 0;
259 	header->mss = 0;
260 
261 	/* Enqueue I/O buffer */
262 	if ( ( rc = usb_stream ( &smscusb->usbnet.out, iobuf, 0 ) ) != 0 )
263 		return rc;
264 
265 	profile_stop ( &smsc75xx_out_profiler );
266 	return 0;
267 }
268 
269 /******************************************************************************
270  *
271  * Network device interface
272  *
273  ******************************************************************************
274  */
275 
276 /**
277  * Open network device
278  *
279  * @v netdev		Network device
280  * @ret rc		Return status code
281  */
smsc75xx_open(struct net_device * netdev)282 static int smsc75xx_open ( struct net_device *netdev ) {
283 	struct smscusb_device *smscusb = netdev->priv;
284 	int rc;
285 
286 	/* Clear stored interrupt status */
287 	smscusb->int_sts = 0;
288 
289 	/* Configure bulk IN empty response */
290 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_HW_CFG,
291 				     SMSC75XX_HW_CFG_BIR ) ) != 0 )
292 		goto err_hw_cfg;
293 
294 	/* Open USB network device */
295 	if ( ( rc = usbnet_open ( &smscusb->usbnet ) ) != 0 ) {
296 		DBGC ( smscusb, "SMSC75XX %p could not open: %s\n",
297 		       smscusb, strerror ( rc ) );
298 		goto err_open;
299 	}
300 
301 	/* Configure interrupt endpoint */
302 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_INT_EP_CTL,
303 				     ( SMSC75XX_INT_EP_CTL_RDFO_EN |
304 				       SMSC75XX_INT_EP_CTL_PHY_EN ) ) ) != 0 )
305 		goto err_int_ep_ctl;
306 
307 	/* Configure bulk IN delay */
308 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_BULK_IN_DLY,
309 				     SMSC75XX_BULK_IN_DLY_SET ( 0 ) ) ) != 0 )
310 		goto err_bulk_in_dly;
311 
312 	/* Configure receive filters */
313 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_RFE_CTL,
314 				     ( SMSC75XX_RFE_CTL_AB |
315 				       SMSC75XX_RFE_CTL_AM |
316 				       SMSC75XX_RFE_CTL_AU ) ) ) != 0 )
317 		goto err_rfe_ctl;
318 
319 	/* Configure receive FIFO */
320 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_FCT_RX_CTL,
321 				     ( SMSC75XX_FCT_RX_CTL_EN |
322 				       SMSC75XX_FCT_RX_CTL_BAD ) ) ) != 0 )
323 		goto err_fct_rx_ctl;
324 
325 	/* Configure transmit FIFO */
326 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_FCT_TX_CTL,
327 				     SMSC75XX_FCT_TX_CTL_EN ) ) != 0 )
328 		goto err_fct_tx_ctl;
329 
330 	/* Configure receive datapath */
331 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_MAC_RX,
332 				     ( SMSC75XX_MAC_RX_MAX_SIZE_DEFAULT |
333 				       SMSC75XX_MAC_RX_FCS |
334 				       SMSC75XX_MAC_RX_EN ) ) ) != 0 )
335 		goto err_mac_rx;
336 
337 	/* Configure transmit datapath */
338 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_MAC_TX,
339 				     SMSC75XX_MAC_TX_EN ) ) != 0 )
340 		goto err_mac_tx;
341 
342 	/* Set MAC address */
343 	if ( ( rc = smscusb_set_address ( smscusb,
344 					  SMSC75XX_RX_ADDR_BASE ) ) != 0 )
345 		goto err_set_address;
346 
347 	/* Set MAC address perfect filter */
348 	if ( ( rc = smscusb_set_filter ( smscusb,
349 					 SMSC75XX_ADDR_FILT_BASE ) ) != 0 )
350 		goto err_set_filter;
351 
352 	/* Enable PHY interrupts and update link status */
353 	if ( ( rc = smscusb_mii_open ( smscusb, SMSC75XX_MII_PHY_INTR_MASK,
354 				       ( SMSC75XX_PHY_INTR_ANEG_DONE |
355 					 SMSC75XX_PHY_INTR_LINK_DOWN ) ) ) != 0)
356 		goto err_mii_open;
357 
358 	return 0;
359 
360  err_mii_open:
361  err_set_filter:
362  err_set_address:
363  err_mac_tx:
364  err_mac_rx:
365  err_fct_tx_ctl:
366  err_fct_rx_ctl:
367  err_rfe_ctl:
368  err_bulk_in_dly:
369  err_int_ep_ctl:
370 	usbnet_close ( &smscusb->usbnet );
371  err_open:
372  err_hw_cfg:
373 	smsc75xx_reset ( smscusb );
374 	return rc;
375 }
376 
377 /**
378  * Close network device
379  *
380  * @v netdev		Network device
381  */
smsc75xx_close(struct net_device * netdev)382 static void smsc75xx_close ( struct net_device *netdev ) {
383 	struct smscusb_device *smscusb = netdev->priv;
384 
385 	/* Close USB network device */
386 	usbnet_close ( &smscusb->usbnet );
387 
388 	/* Dump statistics (for debugging) */
389 	if ( DBG_LOG )
390 		smsc75xx_dump_statistics ( smscusb );
391 
392 	/* Reset device */
393 	smsc75xx_reset ( smscusb );
394 }
395 
396 /**
397  * Transmit packet
398  *
399  * @v netdev		Network device
400  * @v iobuf		I/O buffer
401  * @ret rc		Return status code
402  */
smsc75xx_transmit(struct net_device * netdev,struct io_buffer * iobuf)403 int smsc75xx_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
404 	struct smscusb_device *smscusb = netdev->priv;
405 	int rc;
406 
407 	/* Transmit packet */
408 	if ( ( rc = smsc75xx_out_transmit ( smscusb, iobuf ) ) != 0 )
409 		return rc;
410 
411 	return 0;
412 }
413 
414 /**
415  * Poll for completed and received packets
416  *
417  * @v netdev		Network device
418  */
smsc75xx_poll(struct net_device * netdev)419 void smsc75xx_poll ( struct net_device *netdev ) {
420 	struct smscusb_device *smscusb = netdev->priv;
421 	uint32_t int_sts;
422 	int rc;
423 
424 	/* Poll USB bus */
425 	usb_poll ( smscusb->bus );
426 
427 	/* Refill endpoints */
428 	if ( ( rc = usbnet_refill ( &smscusb->usbnet ) ) != 0 )
429 		netdev_rx_err ( netdev, NULL, rc );
430 
431 	/* Do nothing more unless there are interrupts to handle */
432 	int_sts = smscusb->int_sts;
433 	if ( ! int_sts )
434 		return;
435 
436 	/* Check link status if applicable */
437 	if ( int_sts & SMSC75XX_INT_STS_PHY_INT ) {
438 		smscusb_mii_check_link ( smscusb );
439 		int_sts &= ~SMSC75XX_INT_STS_PHY_INT;
440 	}
441 
442 	/* Record RX FIFO overflow if applicable */
443 	if ( int_sts & SMSC75XX_INT_STS_RDFO_INT ) {
444 		DBGC2 ( smscusb, "SMSC75XX %p RX FIFO overflowed\n", smscusb );
445 		netdev_rx_err ( netdev, NULL, -ENOBUFS );
446 		int_sts &= ~SMSC75XX_INT_STS_RDFO_INT;
447 	}
448 
449 	/* Check for unexpected interrupts */
450 	if ( int_sts ) {
451 		DBGC ( smscusb, "SMSC75XX %p unexpected interrupt %#08x\n",
452 		       smscusb, int_sts );
453 		netdev_rx_err ( netdev, NULL, -ENOTTY );
454 	}
455 
456 	/* Clear interrupts */
457 	if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_INT_STS,
458 				     smscusb->int_sts ) ) != 0 )
459 		netdev_rx_err ( netdev, NULL, rc );
460 	smscusb->int_sts = 0;
461 }
462 
463 /** SMSC75xx network device operations */
464 static struct net_device_operations smsc75xx_operations = {
465 	.open		= smsc75xx_open,
466 	.close		= smsc75xx_close,
467 	.transmit	= smsc75xx_transmit,
468 	.poll		= smsc75xx_poll,
469 };
470 
471 /******************************************************************************
472  *
473  * USB interface
474  *
475  ******************************************************************************
476  */
477 
478 /**
479  * Probe device
480  *
481  * @v func		USB function
482  * @v config		Configuration descriptor
483  * @ret rc		Return status code
484  */
smsc75xx_probe(struct usb_function * func,struct usb_configuration_descriptor * config)485 static int smsc75xx_probe ( struct usb_function *func,
486 			    struct usb_configuration_descriptor *config ) {
487 	struct net_device *netdev;
488 	struct smscusb_device *smscusb;
489 	int rc;
490 
491 	/* Allocate and initialise structure */
492 	netdev = alloc_etherdev ( sizeof ( *smscusb ) );
493 	if ( ! netdev ) {
494 		rc = -ENOMEM;
495 		goto err_alloc;
496 	}
497 	netdev_init ( netdev, &smsc75xx_operations );
498 	netdev->dev = &func->dev;
499 	smscusb = netdev->priv;
500 	memset ( smscusb, 0, sizeof ( *smscusb ) );
501 	smscusb_init ( smscusb, netdev, func, &smsc75xx_in_operations );
502 	smscusb_mii_init ( smscusb, SMSC75XX_MII_BASE,
503 			   SMSC75XX_MII_PHY_INTR_SOURCE );
504 	usb_refill_init ( &smscusb->usbnet.in, 0, SMSC75XX_IN_MTU,
505 			  SMSC75XX_IN_MAX_FILL );
506 	DBGC ( smscusb, "SMSC75XX %p on %s\n", smscusb, func->name );
507 
508 	/* Describe USB network device */
509 	if ( ( rc = usbnet_describe ( &smscusb->usbnet, config ) ) != 0 ) {
510 		DBGC ( smscusb, "SMSC75XX %p could not describe: %s\n",
511 		       smscusb, strerror ( rc ) );
512 		goto err_describe;
513 	}
514 
515 	/* Reset device */
516 	if ( ( rc = smsc75xx_reset ( smscusb ) ) != 0 )
517 		goto err_reset;
518 
519 	/* Read MAC address */
520 	if ( ( rc = smscusb_eeprom_fetch_mac ( smscusb,
521 					       SMSC75XX_E2P_BASE ) ) != 0 )
522 		goto err_fetch_mac;
523 
524 	/* Register network device */
525 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
526 		goto err_register;
527 
528 	usb_func_set_drvdata ( func, netdev );
529 	return 0;
530 
531 	unregister_netdev ( netdev );
532  err_register:
533  err_fetch_mac:
534  err_reset:
535  err_describe:
536 	netdev_nullify ( netdev );
537 	netdev_put ( netdev );
538  err_alloc:
539 	return rc;
540 }
541 
542 /**
543  * Remove device
544  *
545  * @v func		USB function
546  */
smsc75xx_remove(struct usb_function * func)547 static void smsc75xx_remove ( struct usb_function *func ) {
548 	struct net_device *netdev = usb_func_get_drvdata ( func );
549 
550 	unregister_netdev ( netdev );
551 	netdev_nullify ( netdev );
552 	netdev_put ( netdev );
553 }
554 
555 /** SMSC75xx device IDs */
556 static struct usb_device_id smsc75xx_ids[] = {
557 	{
558 		.name = "smsc7500",
559 		.vendor = 0x0424,
560 		.product = 0x7500,
561 	},
562 	{
563 		.name = "smsc7505",
564 		.vendor = 0x0424,
565 		.product = 0x7505,
566 	},
567 };
568 
569 /** SMSC LAN75xx driver */
570 struct usb_driver smsc75xx_driver __usb_driver = {
571 	.ids = smsc75xx_ids,
572 	.id_count = ( sizeof ( smsc75xx_ids ) / sizeof ( smsc75xx_ids[0] ) ),
573 	.class = USB_CLASS_ID ( 0xff, 0x00, 0xff ),
574 	.score = USB_SCORE_NORMAL,
575 	.probe = smsc75xx_probe,
576 	.remove = smsc75xx_remove,
577 };
578