Browse Source

[smscusb] Abstract out common SMSC USB device functionality

The smsc75xx and smsc95xx drivers include a substantial amount of
identical functionality, varying only in the base address of register
sets.  Abstract out this common functionality to allow code to be
shared between the drivers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
5a7558447a
3 changed files with 826 additions and 0 deletions
  1. 523
    0
      src/drivers/net/smscusb.c
  2. 302
    0
      src/drivers/net/smscusb.h
  3. 1
    0
      src/include/ipxe/errfile.h

+ 523
- 0
src/drivers/net/smscusb.c View File

@@ -0,0 +1,523 @@
1
+/*
2
+ * Copyright (C) 2017 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 <errno.h>
28
+#include <unistd.h>
29
+#include <ipxe/usb.h>
30
+#include <ipxe/usbnet.h>
31
+#include <ipxe/ethernet.h>
32
+#include <ipxe/profile.h>
33
+#include "smscusb.h"
34
+
35
+/** @file
36
+ *
37
+ * SMSC USB Ethernet drivers
38
+ *
39
+ */
40
+
41
+/** Interrupt completion profiler */
42
+static struct profiler smscusb_intr_profiler __profiler =
43
+	{ .name = "smscusb.intr" };
44
+
45
+/******************************************************************************
46
+ *
47
+ * EEPROM access
48
+ *
49
+ ******************************************************************************
50
+ */
51
+
52
+/**
53
+ * Wait for EEPROM to become idle
54
+ *
55
+ * @v smscusb		SMSC USB device
56
+ * @v e2p_base		E2P register base
57
+ * @ret rc		Return status code
58
+ */
59
+static int smscusb_eeprom_wait ( struct smscusb_device *smscusb,
60
+				 unsigned int e2p_base ) {
61
+	uint32_t e2p_cmd;
62
+	unsigned int i;
63
+	int rc;
64
+
65
+	/* Wait for EPC_BSY to become clear */
66
+	for ( i = 0 ; i < SMSCUSB_EEPROM_MAX_WAIT_MS ; i++ ) {
67
+
68
+		/* Read E2P_CMD and check EPC_BSY */
69
+		if ( ( rc = smscusb_readl ( smscusb,
70
+					    ( e2p_base + SMSCUSB_E2P_CMD ),
71
+					    &e2p_cmd ) ) != 0 )
72
+			return rc;
73
+		if ( ! ( e2p_cmd & SMSCUSB_E2P_CMD_EPC_BSY ) )
74
+			return 0;
75
+
76
+		/* Delay */
77
+		mdelay ( 1 );
78
+	}
79
+
80
+	DBGC ( smscusb, "SMSCUSB %p timed out waiting for EEPROM\n",
81
+	       smscusb );
82
+	return -ETIMEDOUT;
83
+}
84
+
85
+/**
86
+ * Read byte from EEPROM
87
+ *
88
+ * @v smscusb		SMSC USB device
89
+ * @v e2p_base		E2P register base
90
+ * @v address		EEPROM address
91
+ * @ret byte		Byte read, or negative error
92
+ */
93
+static int smscusb_eeprom_read_byte ( struct smscusb_device *smscusb,
94
+				      unsigned int e2p_base,
95
+				      unsigned int address ) {
96
+	uint32_t e2p_cmd;
97
+	uint32_t e2p_data;
98
+	int rc;
99
+
100
+	/* Wait for EEPROM to become idle */
101
+	if ( ( rc = smscusb_eeprom_wait ( smscusb, e2p_base ) ) != 0 )
102
+		return rc;
103
+
104
+	/* Initiate read command */
105
+	e2p_cmd = ( SMSCUSB_E2P_CMD_EPC_BSY | SMSCUSB_E2P_CMD_EPC_CMD_READ |
106
+		    SMSCUSB_E2P_CMD_EPC_ADDR ( address ) );
107
+	if ( ( rc = smscusb_writel ( smscusb, ( e2p_base + SMSCUSB_E2P_CMD ),
108
+				     e2p_cmd ) ) != 0 )
109
+		return rc;
110
+
111
+	/* Wait for command to complete */
112
+	if ( ( rc = smscusb_eeprom_wait ( smscusb, e2p_base ) ) != 0 )
113
+		return rc;
114
+
115
+	/* Read EEPROM data */
116
+	if ( ( rc = smscusb_readl ( smscusb, ( e2p_base + SMSCUSB_E2P_DATA ),
117
+				    &e2p_data ) ) != 0 )
118
+		return rc;
119
+
120
+	return SMSCUSB_E2P_DATA_GET ( e2p_data );
121
+}
122
+
123
+/**
124
+ * Read data from EEPROM
125
+ *
126
+ * @v smscusb		SMSC USB device
127
+ * @v e2p_base		E2P register base
128
+ * @v address		EEPROM address
129
+ * @v data		Data buffer
130
+ * @v len		Length of data
131
+ * @ret rc		Return status code
132
+ */
133
+static int smscusb_eeprom_read ( struct smscusb_device *smscusb,
134
+				 unsigned int e2p_base, unsigned int address,
135
+				 void *data, size_t len ) {
136
+	uint8_t *bytes;
137
+	int byte;
138
+
139
+	/* Read bytes */
140
+	for ( bytes = data ; len-- ; address++, bytes++ ) {
141
+		byte = smscusb_eeprom_read_byte ( smscusb, e2p_base, address );
142
+		if ( byte < 0 )
143
+			return byte;
144
+		*bytes = byte;
145
+	}
146
+
147
+	return 0;
148
+}
149
+
150
+/**
151
+ * Fetch MAC address from EEPROM
152
+ *
153
+ * @v smscusb		SMSC USB device
154
+ * @v e2p_base		E2P register base
155
+ * @ret rc		Return status code
156
+ */
157
+int smscusb_eeprom_fetch_mac ( struct smscusb_device *smscusb,
158
+			       unsigned int e2p_base ) {
159
+	struct net_device *netdev = smscusb->netdev;
160
+	int rc;
161
+
162
+	/* Read MAC address from EEPROM */
163
+	if ( ( rc = smscusb_eeprom_read ( smscusb, e2p_base, SMSCUSB_EEPROM_MAC,
164
+					  netdev->hw_addr, ETH_ALEN ) ) != 0 )
165
+		return rc;
166
+
167
+	/* Check that EEPROM is physically present */
168
+	if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) {
169
+		DBGC ( smscusb, "SMSCUSB %p has no EEPROM (%s)\n",
170
+		       smscusb, eth_ntoa ( netdev->hw_addr ) );
171
+		return -ENODEV;
172
+	}
173
+
174
+	DBGC ( smscusb, "SMSCUSB %p using EEPROM MAC %s\n",
175
+	       smscusb, eth_ntoa ( netdev->hw_addr ) );
176
+	return 0;
177
+}
178
+
179
+/******************************************************************************
180
+ *
181
+ * MII access
182
+ *
183
+ ******************************************************************************
184
+ */
185
+
186
+/**
187
+ * Wait for MII to become idle
188
+ *
189
+ * @v smscusb		SMSC USB device
190
+ * @ret rc		Return status code
191
+ */
192
+static int smscusb_mii_wait ( struct smscusb_device *smscusb ) {
193
+	unsigned int base = smscusb->mii_base;
194
+	uint32_t mii_access;
195
+	unsigned int i;
196
+	int rc;
197
+
198
+	/* Wait for MIIBZY to become clear */
199
+	for ( i = 0 ; i < SMSCUSB_MII_MAX_WAIT_MS ; i++ ) {
200
+
201
+		/* Read MII_ACCESS and check MIIBZY */
202
+		if ( ( rc = smscusb_readl ( smscusb,
203
+					    ( base + SMSCUSB_MII_ACCESS ),
204
+					    &mii_access ) ) != 0 )
205
+			return rc;
206
+		if ( ! ( mii_access & SMSCUSB_MII_ACCESS_MIIBZY ) )
207
+			return 0;
208
+
209
+		/* Delay */
210
+		mdelay ( 1 );
211
+	}
212
+
213
+	DBGC ( smscusb, "SMSCUSB %p timed out waiting for MII\n",
214
+	       smscusb );
215
+	return -ETIMEDOUT;
216
+}
217
+
218
+/**
219
+ * Read from MII register
220
+ *
221
+ * @v mii		MII interface
222
+ * @v reg		Register address
223
+ * @ret value		Data read, or negative error
224
+ */
225
+static int smscusb_mii_read ( struct mii_interface *mii, unsigned int reg ) {
226
+	struct smscusb_device *smscusb =
227
+		container_of ( mii, struct smscusb_device, mii );
228
+	unsigned int base = smscusb->mii_base;
229
+	uint32_t mii_access;
230
+	uint32_t mii_data;
231
+	int rc;
232
+
233
+	/* Wait for MII to become idle */
234
+	if ( ( rc = smscusb_mii_wait ( smscusb ) ) != 0 )
235
+		return rc;
236
+
237
+	/* Initiate read command */
238
+	mii_access = ( SMSCUSB_MII_ACCESS_PHY_ADDRESS |
239
+		       SMSCUSB_MII_ACCESS_MIIRINDA ( reg ) |
240
+		       SMSCUSB_MII_ACCESS_MIIBZY );
241
+	if ( ( rc = smscusb_writel ( smscusb, ( base + SMSCUSB_MII_ACCESS ),
242
+				     mii_access ) ) != 0 )
243
+		return rc;
244
+
245
+	/* Wait for command to complete */
246
+	if ( ( rc = smscusb_mii_wait ( smscusb ) ) != 0 )
247
+		return rc;
248
+
249
+	/* Read MII data */
250
+	if ( ( rc = smscusb_readl ( smscusb, ( base + SMSCUSB_MII_DATA ),
251
+				    &mii_data ) ) != 0 )
252
+		return rc;
253
+
254
+	return SMSCUSB_MII_DATA_GET ( mii_data );
255
+}
256
+
257
+/**
258
+ * Write to MII register
259
+ *
260
+ * @v mii		MII interface
261
+ * @v reg		Register address
262
+ * @v data		Data to write
263
+ * @ret rc		Return status code
264
+ */
265
+static int smscusb_mii_write ( struct mii_interface *mii, unsigned int reg,
266
+			       unsigned int data ) {
267
+	struct smscusb_device *smscusb =
268
+		container_of ( mii, struct smscusb_device, mii );
269
+	unsigned int base = smscusb->mii_base;
270
+	uint32_t mii_access;
271
+	uint32_t mii_data;
272
+	int rc;
273
+
274
+	/* Wait for MII to become idle */
275
+	if ( ( rc = smscusb_mii_wait ( smscusb ) ) != 0 )
276
+		return rc;
277
+
278
+	/* Write MII data */
279
+	mii_data = SMSCUSB_MII_DATA_SET ( data );
280
+	if ( ( rc = smscusb_writel ( smscusb, ( base + SMSCUSB_MII_DATA ),
281
+				     mii_data ) ) != 0 )
282
+		return rc;
283
+
284
+	/* Initiate write command */
285
+	mii_access = ( SMSCUSB_MII_ACCESS_PHY_ADDRESS |
286
+		       SMSCUSB_MII_ACCESS_MIIRINDA ( reg ) |
287
+		       SMSCUSB_MII_ACCESS_MIIWNR |
288
+		       SMSCUSB_MII_ACCESS_MIIBZY );
289
+	if ( ( rc = smscusb_writel ( smscusb, ( base + SMSCUSB_MII_ACCESS ),
290
+				     mii_access ) ) != 0 )
291
+		return rc;
292
+
293
+	/* Wait for command to complete */
294
+	if ( ( rc = smscusb_mii_wait ( smscusb ) ) != 0 )
295
+		return rc;
296
+
297
+	return 0;
298
+}
299
+
300
+/** MII operations */
301
+struct mii_operations smscusb_mii_operations = {
302
+	.read = smscusb_mii_read,
303
+	.write = smscusb_mii_write,
304
+};
305
+
306
+/**
307
+ * Check link status
308
+ *
309
+ * @v smscusb		SMSC USB device
310
+ * @ret rc		Return status code
311
+ */
312
+int smscusb_mii_check_link ( struct smscusb_device *smscusb ) {
313
+	struct net_device *netdev = smscusb->netdev;
314
+	int intr;
315
+	int rc;
316
+
317
+	/* Read PHY interrupt source */
318
+	intr = mii_read ( &smscusb->mii, SMSCUSB_MII_PHY_INTR_SOURCE );
319
+	if ( intr < 0 ) {
320
+		rc = intr;
321
+		DBGC ( smscusb, "SMSCUSB %p could not get PHY interrupt "
322
+		       "source: %s\n", smscusb, strerror ( rc ) );
323
+		return rc;
324
+	}
325
+
326
+	/* Acknowledge PHY interrupt */
327
+	if ( ( rc = mii_write ( &smscusb->mii, SMSCUSB_MII_PHY_INTR_SOURCE,
328
+				intr ) ) != 0 ) {
329
+		DBGC ( smscusb, "SMSCUSB %p could not acknowledge PHY "
330
+		       "interrupt: %s\n", smscusb, strerror ( rc ) );
331
+		return rc;
332
+	}
333
+
334
+	/* Check link status */
335
+	if ( ( rc = mii_check_link ( &smscusb->mii, netdev ) ) != 0 ) {
336
+		DBGC ( smscusb, "SMSCUSB %p could not check link: %s\n",
337
+		       smscusb, strerror ( rc ) );
338
+		return rc;
339
+	}
340
+
341
+	DBGC ( smscusb, "SMSCUSB %p link %s (intr %#04x)\n",
342
+	       smscusb, ( netdev_link_ok ( netdev ) ? "up" : "down" ), intr );
343
+	return 0;
344
+}
345
+
346
+/**
347
+ * Enable PHY interrupts and update link status
348
+ *
349
+ * @v smscusb		SMSC USB device
350
+ * @ret rc		Return status code
351
+ */
352
+int smscusb_mii_open ( struct smscusb_device *smscusb ) {
353
+	int rc;
354
+
355
+	/* Enable PHY interrupts */
356
+	if ( ( rc = mii_write ( &smscusb->mii, SMSCUSB_MII_PHY_INTR_MASK,
357
+				( SMSCUSB_PHY_INTR_ANEG_DONE |
358
+				  SMSCUSB_PHY_INTR_LINK_DOWN ) ) ) != 0 ) {
359
+		DBGC ( smscusb, "SMSCUSB %p could not set PHY interrupt "
360
+		       "mask: %s\n", smscusb, strerror ( rc ) );
361
+		return rc;
362
+	}
363
+
364
+	/* Update link status */
365
+	smscusb_mii_check_link ( smscusb );
366
+
367
+	return 0;
368
+}
369
+
370
+/******************************************************************************
371
+ *
372
+ * Receive filtering
373
+ *
374
+ ******************************************************************************
375
+ */
376
+
377
+/**
378
+ * Set receive address
379
+ *
380
+ * @v smscusb		SMSC USB device
381
+ * @v addr_base		Receive address register base
382
+ * @ret rc		Return status code
383
+ */
384
+int smscusb_set_address ( struct smscusb_device *smscusb,
385
+			  unsigned int addr_base ) {
386
+	struct net_device *netdev = smscusb->netdev;
387
+	union smscusb_mac mac;
388
+	int rc;
389
+
390
+	/* Copy MAC address */
391
+	memset ( &mac, 0, sizeof ( mac ) );
392
+	memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN );
393
+
394
+	/* Write MAC address high register */
395
+	if ( ( rc = smscusb_raw_writel ( smscusb,
396
+					 ( addr_base + SMSCUSB_RX_ADDRH ),
397
+					 mac.addr.h ) ) != 0 )
398
+		return rc;
399
+
400
+	/* Write MAC address low register */
401
+	if ( ( rc = smscusb_raw_writel ( smscusb,
402
+					 ( addr_base + SMSCUSB_RX_ADDRL ),
403
+					 mac.addr.l ) ) != 0 )
404
+		return rc;
405
+
406
+	return 0;
407
+}
408
+
409
+/**
410
+ * Set receive filter
411
+ *
412
+ * @v smscusb		SMSC USB device
413
+ * @v filt_base		Receive filter register base
414
+ * @ret rc		Return status code
415
+ */
416
+int smscusb_set_filter ( struct smscusb_device *smscusb,
417
+			 unsigned int filt_base ) {
418
+	struct net_device *netdev = smscusb->netdev;
419
+	union smscusb_mac mac;
420
+	int rc;
421
+
422
+	/* Copy MAC address */
423
+	memset ( &mac, 0, sizeof ( mac ) );
424
+	memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN );
425
+	mac.addr.h |= cpu_to_le32 ( SMSCUSB_ADDR_FILTH_VALID );
426
+
427
+	/* Write MAC address perfect filter high register */
428
+	if ( ( rc = smscusb_raw_writel ( smscusb,
429
+					 ( filt_base + SMSCUSB_ADDR_FILTH(0) ),
430
+					 mac.addr.h ) ) != 0 )
431
+		return rc;
432
+
433
+	/* Write MAC address perfect filter low register */
434
+	if ( ( rc = smscusb_raw_writel ( smscusb,
435
+					 ( filt_base + SMSCUSB_ADDR_FILTL(0) ),
436
+					 mac.addr.l ) ) != 0 )
437
+		return rc;
438
+
439
+	return 0;
440
+}
441
+
442
+/******************************************************************************
443
+ *
444
+ * Endpoint operations
445
+ *
446
+ ******************************************************************************
447
+ */
448
+
449
+/**
450
+ * Complete interrupt transfer
451
+ *
452
+ * @v ep		USB endpoint
453
+ * @v iobuf		I/O buffer
454
+ * @v rc		Completion status code
455
+ */
456
+static void smscusb_intr_complete ( struct usb_endpoint *ep,
457
+				    struct io_buffer *iobuf, int rc ) {
458
+	struct smscusb_device *smscusb =
459
+		container_of ( ep, struct smscusb_device, usbnet.intr );
460
+	struct net_device *netdev = smscusb->netdev;
461
+	struct smscusb_interrupt *intr;
462
+
463
+	/* Profile completions */
464
+	profile_start ( &smscusb_intr_profiler );
465
+
466
+	/* Ignore packets cancelled when the endpoint closes */
467
+	if ( ! ep->open )
468
+		goto done;
469
+
470
+	/* Record USB errors against the network device */
471
+	if ( rc != 0 ) {
472
+		DBGC ( smscusb, "SMSCUSB %p interrupt failed: %s\n",
473
+		       smscusb, strerror ( rc ) );
474
+		DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
475
+		netdev_rx_err ( netdev, NULL, rc );
476
+		goto done;
477
+	}
478
+
479
+	/* Extract interrupt data */
480
+	if ( iob_len ( iobuf ) != sizeof ( *intr ) ) {
481
+		DBGC ( smscusb, "SMSCUSB %p malformed interrupt\n",
482
+		       smscusb );
483
+		DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
484
+		netdev_rx_err ( netdev, NULL, rc );
485
+		goto done;
486
+	}
487
+	intr = iobuf->data;
488
+
489
+	/* Record interrupt status */
490
+	smscusb->int_sts = le32_to_cpu ( intr->int_sts );
491
+	profile_stop ( &smscusb_intr_profiler );
492
+
493
+ done:
494
+	/* Free I/O buffer */
495
+	free_iob ( iobuf );
496
+}
497
+
498
+/** Interrupt endpoint operations */
499
+struct usb_endpoint_driver_operations smscusb_intr_operations = {
500
+	.complete = smscusb_intr_complete,
501
+};
502
+
503
+/**
504
+ * Complete bulk OUT transfer
505
+ *
506
+ * @v ep		USB endpoint
507
+ * @v iobuf		I/O buffer
508
+ * @v rc		Completion status code
509
+ */
510
+static void smscusb_out_complete ( struct usb_endpoint *ep,
511
+				   struct io_buffer *iobuf, int rc ) {
512
+	struct smscusb_device *smscusb =
513
+		container_of ( ep, struct smscusb_device, usbnet.out );
514
+	struct net_device *netdev = smscusb->netdev;
515
+
516
+	/* Report TX completion */
517
+	netdev_tx_complete_err ( netdev, iobuf, rc );
518
+}
519
+
520
+/** Bulk OUT endpoint operations */
521
+struct usb_endpoint_driver_operations smscusb_out_operations = {
522
+	.complete = smscusb_out_complete,
523
+};

+ 302
- 0
src/drivers/net/smscusb.h View File

@@ -0,0 +1,302 @@
1
+#ifndef _SMSCUSB_H
2
+#define _SMSCUSB_H
3
+
4
+/** @file
5
+ *
6
+ * SMSC USB Ethernet drivers
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
+
12
+#include <stdint.h>
13
+#include <string.h>
14
+#include <byteswap.h>
15
+#include <ipxe/usb.h>
16
+#include <ipxe/usbnet.h>
17
+#include <ipxe/netdevice.h>
18
+#include <ipxe/mii.h>
19
+#include <ipxe/if_ether.h>
20
+
21
+/** Register write command */
22
+#define SMSCUSB_REGISTER_WRITE					\
23
+	( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE |	\
24
+	  USB_REQUEST_TYPE ( 0xa0 ) )
25
+
26
+/** Register read command */
27
+#define SMSCUSB_REGISTER_READ					\
28
+	( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE |	\
29
+	  USB_REQUEST_TYPE ( 0xa1 ) )
30
+
31
+/** Get statistics command */
32
+#define SMSCUSB_GET_STATISTICS					\
33
+	( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE |	\
34
+	  USB_REQUEST_TYPE ( 0xa2 ) )
35
+
36
+/** EEPROM command register offset */
37
+#define SMSCUSB_E2P_CMD 0x000
38
+#define SMSCUSB_E2P_CMD_EPC_BSY		0x80000000UL	/**< EPC busy */
39
+#define SMSCUSB_E2P_CMD_EPC_CMD_READ	0x00000000UL	/**< READ command */
40
+#define SMSCUSB_E2P_CMD_EPC_ADDR(addr) ( (addr) << 0 )	/**< EPC address */
41
+
42
+/** EEPROM data register offset */
43
+#define SMSCUSB_E2P_DATA 0x004
44
+#define SMSCUSB_E2P_DATA_GET(e2p_data) \
45
+	( ( (e2p_data) >> 0 ) & 0xff )			/**< EEPROM data */
46
+
47
+/** MAC address EEPROM address */
48
+#define SMSCUSB_EEPROM_MAC 0x01
49
+
50
+/** Maximum time to wait for EEPROM (in milliseconds) */
51
+#define SMSCUSB_EEPROM_MAX_WAIT_MS 100
52
+
53
+/** MII access register offset */
54
+#define SMSCUSB_MII_ACCESS 0x000
55
+#define SMSCUSB_MII_ACCESS_PHY_ADDRESS	0x00000800UL	/**< PHY address */
56
+#define SMSCUSB_MII_ACCESS_MIIRINDA(addr) ( (addr) << 6 ) /**< MII register */
57
+#define SMSCUSB_MII_ACCESS_MIIWNR	0x00000002UL	/**< MII write */
58
+#define SMSCUSB_MII_ACCESS_MIIBZY	0x00000001UL	/**< MII busy */
59
+
60
+/** MII data register offset */
61
+#define SMSCUSB_MII_DATA 0x004
62
+#define SMSCUSB_MII_DATA_SET(data)	( (data) << 0 )	/**< Set data */
63
+#define SMSCUSB_MII_DATA_GET(mii_data) \
64
+	( ( (mii_data) >> 0 ) & 0xffff )		/**< Get data */
65
+
66
+/** PHY interrupt source MII register */
67
+#define SMSCUSB_MII_PHY_INTR_SOURCE 29
68
+
69
+/** PHY interrupt mask MII register */
70
+#define SMSCUSB_MII_PHY_INTR_MASK 30
71
+
72
+/** PHY interrupt: auto-negotiation complete */
73
+#define SMSCUSB_PHY_INTR_ANEG_DONE 0x0040
74
+
75
+/** PHY interrupt: link down */
76
+#define SMSCUSB_PHY_INTR_LINK_DOWN 0x0010
77
+
78
+/** Maximum time to wait for MII (in milliseconds) */
79
+#define SMSCUSB_MII_MAX_WAIT_MS 100
80
+
81
+/** MAC address */
82
+union smscusb_mac {
83
+	/** MAC receive address registers */
84
+	struct {
85
+		/** MAC receive address low register */
86
+		uint32_t l;
87
+		/** MAC receive address high register */
88
+		uint32_t h;
89
+	} __attribute__ (( packed )) addr;
90
+	/** Raw MAC address */
91
+	uint8_t raw[ETH_ALEN];
92
+};
93
+
94
+/** MAC receive address high register offset */
95
+#define SMSCUSB_RX_ADDRH 0x000
96
+
97
+/** MAC receive address low register offset */
98
+#define SMSCUSB_RX_ADDRL 0x004
99
+
100
+/** MAC address perfect filter N high register offset */
101
+#define SMSCUSB_ADDR_FILTH(n) ( 0x000 + ( 8 * (n) ) )
102
+#define SMSCUSB_ADDR_FILTH_VALID	0x80000000UL	/**< Address valid */
103
+
104
+/** MAC address perfect filter N low register offset */
105
+#define SMSCUSB_ADDR_FILTL(n) ( 0x004 + ( 8 * (n) ) )
106
+
107
+/** Interrupt packet format */
108
+struct smscusb_interrupt {
109
+	/** Current value of INT_STS register */
110
+	uint32_t int_sts;
111
+} __attribute__ (( packed ));
112
+
113
+/** An SMSC USB device */
114
+struct smscusb_device {
115
+	/** USB device */
116
+	struct usb_device *usb;
117
+	/** USB bus */
118
+	struct usb_bus *bus;
119
+	/** Network device */
120
+	struct net_device *netdev;
121
+	/** USB network device */
122
+	struct usbnet_device usbnet;
123
+	/** MII interface */
124
+	struct mii_interface mii;
125
+	/** MII register base */
126
+	uint16_t mii_base;
127
+	/** Interrupt status */
128
+	uint32_t int_sts;
129
+};
130
+
131
+/**
132
+ * Write register (without byte-swapping)
133
+ *
134
+ * @v smscusb		Smscusb device
135
+ * @v address		Register address
136
+ * @v value		Register value
137
+ * @ret rc		Return status code
138
+ */
139
+static int smscusb_raw_writel ( struct smscusb_device *smscusb,
140
+				unsigned int address, uint32_t value ) {
141
+	int rc;
142
+
143
+	/* Write register */
144
+	DBGCIO ( smscusb, "SMSCUSB %p [%03x] <= %08x\n",
145
+		 smscusb, address, le32_to_cpu ( value ) );
146
+	if ( ( rc = usb_control ( smscusb->usb, SMSCUSB_REGISTER_WRITE, 0,
147
+				  address, &value, sizeof ( value ) ) ) != 0 ) {
148
+		DBGC ( smscusb, "SMSCUSB %p could not write %03x: %s\n",
149
+		       smscusb, address, strerror ( rc ) );
150
+		return rc;
151
+	}
152
+
153
+	return 0;
154
+}
155
+
156
+/**
157
+ * Write register
158
+ *
159
+ * @v smscusb		SMSC USB device
160
+ * @v address		Register address
161
+ * @v value		Register value
162
+ * @ret rc		Return status code
163
+ */
164
+static inline __attribute__ (( always_inline )) int
165
+smscusb_writel ( struct smscusb_device *smscusb, unsigned int address,
166
+		 uint32_t value ) {
167
+	int rc;
168
+
169
+	/* Write register */
170
+	if ( ( rc = smscusb_raw_writel ( smscusb, address,
171
+					 cpu_to_le32 ( value ) ) ) != 0 )
172
+		return rc;
173
+
174
+	return 0;
175
+}
176
+
177
+/**
178
+ * Read register (without byte-swapping)
179
+ *
180
+ * @v smscusb		SMSC USB device
181
+ * @v address		Register address
182
+ * @ret value		Register value
183
+ * @ret rc		Return status code
184
+ */
185
+static int smscusb_raw_readl ( struct smscusb_device *smscusb,
186
+			       unsigned int address, uint32_t *value ) {
187
+	int rc;
188
+
189
+	/* Read register */
190
+	if ( ( rc = usb_control ( smscusb->usb, SMSCUSB_REGISTER_READ, 0,
191
+				  address, value, sizeof ( *value ) ) ) != 0 ) {
192
+		DBGC ( smscusb, "SMSCUSB %p could not read %03x: %s\n",
193
+		       smscusb, address, strerror ( rc ) );
194
+		return rc;
195
+	}
196
+	DBGCIO ( smscusb, "SMSCUSB %p [%03x] => %08x\n",
197
+		 smscusb, address, le32_to_cpu ( *value ) );
198
+
199
+	return 0;
200
+}
201
+
202
+/**
203
+ * Read register
204
+ *
205
+ * @v smscusb		SMSC USB device
206
+ * @v address		Register address
207
+ * @ret value		Register value
208
+ * @ret rc		Return status code
209
+ */
210
+static inline __attribute__ (( always_inline )) int
211
+smscusb_readl ( struct smscusb_device *smscusb, unsigned int address,
212
+		uint32_t *value ) {
213
+	int rc;
214
+
215
+	/* Read register */
216
+	if ( ( rc = smscusb_raw_readl ( smscusb, address, value ) ) != 0 )
217
+		return rc;
218
+	le32_to_cpus ( value );
219
+
220
+	return 0;
221
+}
222
+
223
+/**
224
+ * Get statistics
225
+ *
226
+ * @v smscusb		SMSC USB device
227
+ * @v index		Statistics set index
228
+ * @v data		Statistics data to fill in
229
+ * @v len		Length of statistics data
230
+ * @ret rc		Return status code
231
+ */
232
+static inline __attribute__ (( always_inline )) int
233
+smscusb_get_statistics ( struct smscusb_device *smscusb, unsigned int index,
234
+			 void *data, size_t len ) {
235
+	int rc;
236
+
237
+	/* Read statistics */
238
+	if ( ( rc = usb_control ( smscusb->usb, SMSCUSB_GET_STATISTICS, 0,
239
+				  index, data, len ) ) != 0 ) {
240
+		DBGC ( smscusb, "SMSCUSB %p could not get statistics set %d: "
241
+		       "%s\n", smscusb, index, strerror ( rc ) );
242
+		return rc;
243
+	}
244
+
245
+	return 0;
246
+}
247
+
248
+/** Interrupt maximum fill level
249
+ *
250
+ * This is a policy decision.
251
+ */
252
+#define SMSCUSB_INTR_MAX_FILL 2
253
+
254
+extern struct usb_endpoint_driver_operations smscusb_intr_operations;
255
+extern struct usb_endpoint_driver_operations smscusb_out_operations;
256
+extern struct mii_operations smscusb_mii_operations;
257
+
258
+/**
259
+ * Initialise SMSC USB device
260
+ *
261
+ * @v smscusb		SMSC USB device
262
+ * @v netdev		Network device
263
+ * @v func		USB function
264
+ * @v in		Bulk IN endpoint operations
265
+ */
266
+static inline __attribute__ (( always_inline )) void
267
+smscusb_init ( struct smscusb_device *smscusb, struct net_device *netdev,
268
+	       struct usb_function *func,
269
+	       struct usb_endpoint_driver_operations *in ) {
270
+	struct usb_device *usb = func->usb;
271
+
272
+	smscusb->usb = usb;
273
+	smscusb->bus = usb->port->hub->bus;
274
+	smscusb->netdev = netdev;
275
+	usbnet_init ( &smscusb->usbnet, func, &smscusb_intr_operations, in,
276
+		      &smscusb_out_operations );
277
+	usb_refill_init ( &smscusb->usbnet.intr, 0, 0, SMSCUSB_INTR_MAX_FILL );
278
+}
279
+
280
+/**
281
+ * Initialise SMSC USB device MII interface
282
+ *
283
+ * @v smscusb		SMSC USB device
284
+ * @v mii_base		MII register base
285
+ */
286
+static inline __attribute__ (( always_inline )) void
287
+smscusb_mii_init ( struct smscusb_device *smscusb, unsigned int mii_base ) {
288
+
289
+	mii_init ( &smscusb->mii, &smscusb_mii_operations );
290
+	smscusb->mii_base = mii_base;
291
+}
292
+
293
+extern int smscusb_eeprom_fetch_mac ( struct smscusb_device *smscusb,
294
+				      unsigned int e2p_base );
295
+extern int smscusb_mii_check_link ( struct smscusb_device *smscusb );
296
+extern int smscusb_mii_open ( struct smscusb_device *smscusb );
297
+extern int smscusb_set_address ( struct smscusb_device *smscusb,
298
+				 unsigned int addr_base );
299
+extern int smscusb_set_filter ( struct smscusb_device *smscusb,
300
+				unsigned int filt_base );
301
+
302
+#endif /* _SMSCUSB_H */

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -200,6 +200,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
200 200
 #define ERRFILE_sfc_hunt	     ( ERRFILE_DRIVER | 0x00c40000 )
201 201
 #define ERRFILE_efx_hunt	     ( ERRFILE_DRIVER | 0x00c50000 )
202 202
 #define ERRFILE_exanic		     ( ERRFILE_DRIVER | 0x00c60000 )
203
+#define ERRFILE_smscusb		     ( ERRFILE_DRIVER | 0x00c70000 )
203 204
 
204 205
 #define ERRFILE_aoe			( ERRFILE_NET | 0x00000000 )
205 206
 #define ERRFILE_arp			( ERRFILE_NET | 0x00010000 )

Loading…
Cancel
Save