Browse Source

[icplus] Add driver for IC+ network card

Signed-off-by: Sylvie Barlow <sylvie.c.barlow@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Sylvie Barlow 6 years ago
parent
commit
960d1e36b0
3 changed files with 1016 additions and 0 deletions
  1. 809
    0
      src/drivers/net/icplus.c
  2. 206
    0
      src/drivers/net/icplus.h
  3. 1
    0
      src/include/ipxe/errfile.h

+ 809
- 0
src/drivers/net/icplus.c View File

@@ -0,0 +1,809 @@
1
+/*
2
+ * Copyright (C) 2018 Sylvie Barlow <sylvie.c.barlow@gmail.com>.
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 <stdint.h>
27
+#include <string.h>
28
+#include <unistd.h>
29
+#include <errno.h>
30
+#include <byteswap.h>
31
+#include <ipxe/netdevice.h>
32
+#include <ipxe/ethernet.h>
33
+#include <ipxe/if_ether.h>
34
+#include <ipxe/iobuf.h>
35
+#include <ipxe/malloc.h>
36
+#include <ipxe/pci.h>
37
+#include "icplus.h"
38
+
39
+/** @file
40
+ *
41
+ * IC+ network driver
42
+ *
43
+ */
44
+
45
+/******************************************************************************
46
+ *
47
+ * Device reset
48
+ *
49
+ ******************************************************************************
50
+ */
51
+
52
+/**
53
+ * Reset hardware
54
+ *
55
+ * @v icp		IC+ device
56
+ * @ret rc		Return status code
57
+ */
58
+static int icplus_reset ( struct icplus_nic *icp ) {
59
+	uint32_t asicctrl;
60
+	unsigned int i;
61
+
62
+	/* Trigger reset */
63
+	writel ( ( ICP_ASICCTRL_GLOBALRESET | ICP_ASICCTRL_DMA |
64
+		   ICP_ASICCTRL_FIFO | ICP_ASICCTRL_NETWORK | ICP_ASICCTRL_HOST |
65
+		   ICP_ASICCTRL_AUTOINIT ), ( icp->regs + ICP_ASICCTRL ) );
66
+
67
+	/* Wait for reset to complete */
68
+	for ( i = 0 ; i < ICP_RESET_MAX_WAIT_MS ; i++ ) {
69
+
70
+		/* Check if device is ready */
71
+		asicctrl = readl ( icp->regs + ICP_ASICCTRL );
72
+		if ( ! ( asicctrl & ICP_ASICCTRL_RESETBUSY ) )
73
+			return 0;
74
+
75
+		/* Delay */
76
+		mdelay ( 1 );
77
+	}
78
+
79
+	DBGC ( icp, "ICPLUS %p timed out waiting for reset (asicctrl %#08x)\n",
80
+	       icp, asicctrl );
81
+	return -ETIMEDOUT;
82
+}
83
+
84
+/******************************************************************************
85
+ *
86
+ * EEPROM interface
87
+ *
88
+ ******************************************************************************
89
+ */
90
+
91
+/**
92
+ * Read data from EEPROM
93
+ *
94
+ * @v nvs		NVS device
95
+ * @v address		Address from which to read
96
+ * @v data		Data buffer
97
+ * @v len		Length of data buffer
98
+ * @ret rc		Return status code
99
+ */
100
+static int icplus_read_eeprom ( struct nvs_device *nvs, unsigned int address,
101
+				void *data, size_t len ) {
102
+	struct icplus_nic *icp =
103
+		container_of ( nvs, struct icplus_nic, eeprom );
104
+	unsigned int i;
105
+	uint16_t eepromctrl;
106
+	uint16_t *data_word = data;
107
+
108
+	/* Sanity check.  We advertise a blocksize of one word, so
109
+	 * should only ever receive single-word requests.
110
+	 */
111
+	assert ( len == sizeof ( *data_word ) );
112
+
113
+	/* Initiate read */
114
+	writew ( ( ICP_EEPROMCTRL_OPCODE_READ |
115
+		   ICP_EEPROMCTRL_ADDRESS ( address ) ),
116
+		 ( icp->regs + ICP_EEPROMCTRL ) );
117
+
118
+	/* Wait for read to complete */
119
+	for ( i = 0 ; i < ICP_EEPROM_MAX_WAIT_MS ; i++ ) {
120
+
121
+		/* If read is not complete, delay 1ms and retry */
122
+		eepromctrl = readw ( icp->regs + ICP_EEPROMCTRL );
123
+		if ( eepromctrl & ICP_EEPROMCTRL_BUSY ) {
124
+			mdelay ( 1 );
125
+			continue;
126
+		}
127
+
128
+		/* Extract data */
129
+		*data_word = cpu_to_le16 ( readw ( icp->regs + ICP_EEPROMDATA ));
130
+		return 0;
131
+	}
132
+
133
+	DBGC ( icp, "ICPLUS %p timed out waiting for EEPROM read\n", icp );
134
+	return -ETIMEDOUT;
135
+}
136
+
137
+/**
138
+ * Write data to EEPROM
139
+ *
140
+ * @v nvs		NVS device
141
+ * @v address		Address to which to write
142
+ * @v data		Data buffer
143
+ * @v len		Length of data buffer
144
+ * @ret rc		Return status code
145
+ */
146
+static int icplus_write_eeprom ( struct nvs_device *nvs,
147
+				 unsigned int address __unused,
148
+				 const void *data __unused,
149
+				 size_t len __unused ) {
150
+	struct icplus_nic *icp =
151
+		container_of ( nvs, struct icplus_nic, eeprom );
152
+
153
+	DBGC ( icp, "ICPLUS %p EEPROM write not supported\n", icp );
154
+	return -ENOTSUP;
155
+}
156
+
157
+/**
158
+ * Initialise EEPROM
159
+ *
160
+ * @v icp		IC+ device
161
+ */
162
+static void icplus_init_eeprom ( struct icplus_nic *icp ) {
163
+
164
+	/* The hardware supports only single-word reads */
165
+	icp->eeprom.word_len_log2 = ICP_EEPROM_WORD_LEN_LOG2;
166
+	icp->eeprom.size = ICP_EEPROM_MIN_SIZE_WORDS;
167
+	icp->eeprom.block_size = 1;
168
+	icp->eeprom.read = icplus_read_eeprom;
169
+	icp->eeprom.write = icplus_write_eeprom;
170
+}
171
+
172
+/******************************************************************************
173
+ *
174
+ * MII interface
175
+ *
176
+ ******************************************************************************
177
+ */
178
+
179
+/** Pin mapping for MII bit-bashing interface */
180
+static const uint8_t icplus_mii_bits[] = {
181
+	[MII_BIT_MDC]	= ICP_PHYCTRL_MGMTCLK,
182
+	[MII_BIT_MDIO]	= ICP_PHYCTRL_MGMTDATA,
183
+	[MII_BIT_DRIVE]	= ICP_PHYCTRL_MGMTDIR,
184
+};
185
+
186
+/**
187
+ * Read input bit
188
+ *
189
+ * @v basher		Bit-bashing interface
190
+ * @v bit_id		Bit number
191
+ * @ret zero		Input is a logic 0
192
+ * @ret non-zero	Input is a logic 1
193
+ */
194
+static int icplus_mii_read_bit ( struct bit_basher *basher,
195
+				 unsigned int bit_id ) {
196
+	struct icplus_nic *icp = container_of ( basher, struct icplus_nic,
197
+						miibit.basher );
198
+	uint8_t mask = icplus_mii_bits[bit_id];
199
+	uint8_t reg;
200
+
201
+	DBG_DISABLE ( DBGLVL_IO );
202
+	reg = readb ( icp->regs + ICP_PHYCTRL );
203
+	DBG_ENABLE ( DBGLVL_IO );
204
+	return ( reg & mask );
205
+}
206
+
207
+/**
208
+ * Set/clear output bit
209
+ *
210
+ * @v basher		Bit-bashing interface
211
+ * @v bit_id		Bit number
212
+ * @v data		Value to write
213
+ */
214
+static void icplus_mii_write_bit ( struct bit_basher *basher,
215
+				   unsigned int bit_id, unsigned long data ) {
216
+	struct icplus_nic *icp = container_of ( basher, struct icplus_nic,
217
+						miibit.basher );
218
+	uint8_t mask = icplus_mii_bits[bit_id];
219
+	uint8_t reg;
220
+
221
+	DBG_DISABLE ( DBGLVL_IO );
222
+	reg = readb ( icp->regs + ICP_PHYCTRL );
223
+	reg &= ~mask;
224
+	reg |= ( data & mask );
225
+	writeb ( reg, icp->regs + ICP_PHYCTRL );
226
+	readb ( icp->regs + ICP_PHYCTRL ); /* Ensure write reaches chip */
227
+	DBG_ENABLE ( DBGLVL_IO );
228
+}
229
+
230
+/** MII bit-bashing interface */
231
+static struct bit_basher_operations icplus_basher_ops = {
232
+	.read = icplus_mii_read_bit,
233
+	.write = icplus_mii_write_bit,
234
+};
235
+
236
+/******************************************************************************
237
+ *
238
+ * Link state
239
+ *
240
+ ******************************************************************************
241
+ */
242
+
243
+/**
244
+ * Configure PHY
245
+ *
246
+ * @v icp		IC+ device
247
+ * @ret rc		Return status code
248
+ */
249
+static int icplus_init_phy ( struct icplus_nic *icp ) {
250
+	uint32_t asicctrl;
251
+	int rc;
252
+
253
+	/* Find PHY address */
254
+	if ( ( rc = mii_find ( &icp->mii ) ) != 0 ) {
255
+		DBGC ( icp, "ICPLUS %p could not find PHY address: %s\n",
256
+		       icp, strerror ( rc ) );
257
+		return rc;
258
+	}
259
+
260
+	/* Configure PHY to advertise 1000Mbps if applicable */
261
+	asicctrl = readl ( icp->regs + ICP_ASICCTRL );
262
+	if ( asicctrl & ICP_ASICCTRL_PHYSPEED1000 ) {
263
+		if ( ( rc = mii_write ( &icp->mii, MII_CTRL1000,
264
+					ADVERTISE_1000FULL ) ) != 0 ) {
265
+			DBGC ( icp, "ICPLUS %p could not advertise 1000Mbps: "
266
+			       "%s\n", icp, strerror ( rc ) );
267
+			return rc;
268
+		}
269
+	}
270
+
271
+	/* Reset PHY */
272
+	if ( ( rc = mii_reset ( &icp->mii ) ) != 0 ) {
273
+		DBGC ( icp, "ICPLUS %p could not reset PHY: %s\n",
274
+		       icp, strerror ( rc ) );
275
+		return rc;
276
+	}
277
+
278
+	return 0;
279
+}
280
+
281
+/**
282
+ * Check link state
283
+ *
284
+ * @v netdev		Network device
285
+ */
286
+static void icplus_check_link ( struct net_device *netdev ) {
287
+	struct icplus_nic *icp = netdev->priv;
288
+	uint8_t phyctrl;
289
+
290
+	/* Read link status */
291
+	phyctrl = readb ( icp->regs + ICP_PHYCTRL );
292
+	DBGC ( icp, "ICPLUS %p PHY control is %02x\n", icp, phyctrl );
293
+
294
+	/* Update network device */
295
+	if ( phyctrl & ICP_PHYCTRL_LINKSPEED ) {
296
+		netdev_link_up ( netdev );
297
+	} else {
298
+		netdev_link_down ( netdev );
299
+	}
300
+}
301
+
302
+/******************************************************************************
303
+ *
304
+ * Network device interface
305
+ *
306
+ ******************************************************************************
307
+ */
308
+
309
+/**
310
+ * Set descriptor ring base address
311
+ *
312
+ * @v icp		IC+ device
313
+ * @v offset		Register offset
314
+ * @v address		Base address
315
+ */
316
+static inline void icplus_set_base ( struct icplus_nic *icp, unsigned int offset,
317
+				     void *base ) {
318
+	physaddr_t phys = virt_to_bus ( base );
319
+
320
+	/* Program base address registers */
321
+	writel ( ( phys & 0xffffffffUL ),
322
+		 ( icp->regs + offset + ICP_BASE_LO ) );
323
+	if ( sizeof ( phys ) > sizeof ( uint32_t ) ) {
324
+		writel ( ( ( ( uint64_t ) phys ) >> 32 ),
325
+			 ( icp->regs + offset + ICP_BASE_HI ) );
326
+	} else {
327
+		writel ( 0, ( icp->regs + offset + ICP_BASE_HI ) );
328
+	}
329
+}
330
+
331
+/**
332
+ * Create descriptor ring
333
+ *
334
+ * @v icp		IC+ device
335
+ * @v ring		Descriptor ring
336
+ * @ret rc		Return status code
337
+ */
338
+static int icplus_create_ring ( struct icplus_nic *icp, struct icplus_ring *ring ) {
339
+	size_t len = ( sizeof ( ring->entry[0] ) * ICP_NUM_DESC );
340
+	int rc;
341
+	unsigned int i;
342
+	struct icplus_descriptor *desc;
343
+	struct icplus_descriptor *next;
344
+
345
+	/* Allocate descriptor ring */
346
+	ring->entry = malloc_dma ( len, ICP_ALIGN );
347
+	if ( ! ring->entry ) {
348
+		rc = -ENOMEM;
349
+		goto err_alloc;
350
+	}
351
+
352
+	/* Initialise descriptor ring */
353
+	memset ( ring->entry, 0, len );
354
+	for ( i = 0 ; i < ICP_NUM_DESC ; i++ ) {
355
+		desc = &ring->entry[i];
356
+		next = &ring->entry[ ( i + 1 ) % ICP_NUM_DESC ];
357
+		desc->next = cpu_to_le64 ( virt_to_bus ( next ) );
358
+		desc->flags = ( ICP_TX_UNALIGN | ICP_TX_INDICATE );
359
+		desc->control = ( ICP_TX_SOLE_FRAG | ICP_DONE );
360
+	}
361
+
362
+	/* Reset transmit producer & consumer counters */
363
+	ring->prod = 0;
364
+	ring->cons = 0;
365
+
366
+	DBGC ( icp, "ICP %p %s ring at [%#08lx,%#08lx)\n",
367
+	       icp, ( ( ring->listptr == ICP_TFDLISTPTR ) ? "TX" : "RX" ),
368
+	       virt_to_bus ( ring->entry ),
369
+	       ( virt_to_bus ( ring->entry ) + len ) );
370
+	return 0;
371
+
372
+	free_dma ( ring->entry, len );
373
+	ring->entry = NULL;
374
+ err_alloc:
375
+	return rc;
376
+}
377
+
378
+/**
379
+ * Destroy descriptor ring
380
+ *
381
+ * @v icp		IC+ device
382
+ * @v ring		Descriptor ring
383
+ */
384
+static void icplus_destroy_ring ( struct icplus_nic *icp __unused,
385
+				  struct icplus_ring *ring ) {
386
+	size_t len = ( sizeof ( ring->entry[0] ) * ICP_NUM_DESC );
387
+
388
+	/* Free descriptor ring */
389
+	free_dma ( ring->entry, len );
390
+	ring->entry = NULL;
391
+}
392
+
393
+/**
394
+ * Refill receive descriptor ring
395
+ *
396
+ * @v icp		IC+ device
397
+ */
398
+void icplus_refill_rx ( struct icplus_nic *icp ) {
399
+	struct icplus_descriptor *desc;
400
+	struct io_buffer *iobuf;
401
+	unsigned int rx_idx;
402
+	physaddr_t address;
403
+	unsigned int refilled = 0;
404
+
405
+	/* Refill ring */
406
+	while ( ( icp->rx.prod - icp->rx.cons ) < ICP_NUM_DESC ) {
407
+
408
+		/* Allocate I/O buffer */
409
+		iobuf = alloc_iob ( ICP_RX_MAX_LEN );
410
+		if ( ! iobuf ) {
411
+			/* Wait for next refill */
412
+			break;
413
+		}
414
+
415
+		/* Get next receive descriptor */
416
+		rx_idx = ( icp->rx.prod++ % ICP_NUM_DESC );
417
+		desc = &icp->rx.entry[rx_idx];
418
+
419
+		/* Populate receive descriptor */
420
+		address = virt_to_bus ( iobuf->data );
421
+	        desc->data.address = cpu_to_le64 ( address );
422
+		desc->data.len = cpu_to_le16 ( ICP_RX_MAX_LEN );
423
+		wmb();
424
+		desc->control = 0;
425
+
426
+		/* Record I/O buffer */
427
+		assert ( icp->rx_iobuf[rx_idx] == NULL );
428
+		icp->rx_iobuf[rx_idx] = iobuf;
429
+
430
+		DBGC2 ( icp, "ICP %p RX %d is [%llx,%llx)\n", icp, rx_idx,
431
+			( ( unsigned long long ) address ),
432
+			( ( unsigned long long ) address + ICP_RX_MAX_LEN ) );
433
+		refilled++;
434
+	}
435
+
436
+	/* Push descriptors to card, if applicable */
437
+	if ( refilled ) {
438
+		wmb();
439
+		writew ( ICP_DMACTRL_RXPOLLNOW, icp->regs + ICP_DMACTRL );
440
+	}
441
+}
442
+
443
+/**
444
+ * Open network device
445
+ *
446
+ * @v netdev		Network device
447
+ * @ret rc		Return status code
448
+ */
449
+static int icplus_open ( struct net_device *netdev ) {
450
+	struct icplus_nic *icp = netdev->priv;
451
+	int rc;
452
+
453
+	/* Create transmit descriptor ring */
454
+	if ( ( rc = icplus_create_ring ( icp, &icp->tx ) ) != 0 )
455
+		goto err_create_tx;
456
+
457
+	/* Create receive descriptor ring */
458
+	if ( ( rc = icplus_create_ring ( icp, &icp->rx ) ) != 0 )
459
+		goto err_create_rx;
460
+
461
+	/* Program descriptor base address */
462
+	icplus_set_base ( icp, icp->tx.listptr, icp->tx.entry );
463
+	icplus_set_base ( icp, icp->rx.listptr, icp->rx.entry );
464
+
465
+	/* Enable receive mode */
466
+	writew ( ( ICP_RXMODE_UNICAST | ICP_RXMODE_MULTICAST |
467
+		   ICP_RXMODE_BROADCAST | ICP_RXMODE_ALLFRAMES ),
468
+		 icp->regs + ICP_RXMODE );
469
+
470
+	/* Enable transmitter and receiver */
471
+	writel ( ( ICP_MACCTRL_TXENABLE | ICP_MACCTRL_RXENABLE |
472
+		   ICP_MACCTRL_DUPLEX ), icp->regs + ICP_MACCTRL );
473
+
474
+	/* Fill receive ring */
475
+	icplus_refill_rx ( icp );
476
+
477
+	/* Check link state */
478
+	icplus_check_link ( netdev );
479
+
480
+	return 0;
481
+
482
+	icplus_reset ( icp );
483
+	icplus_destroy_ring ( icp, &icp->rx );
484
+ err_create_rx:
485
+	icplus_destroy_ring ( icp, &icp->tx );
486
+ err_create_tx:
487
+	return rc;
488
+}
489
+
490
+/**
491
+ * Close network device
492
+ *
493
+ * @v netdev		Network device
494
+ */
495
+static void icplus_close ( struct net_device *netdev ) {
496
+	struct icplus_nic *icp = netdev->priv;
497
+	unsigned int i;
498
+
499
+	/* Perform global reset */
500
+	icplus_reset ( icp );
501
+
502
+	/* Destroy receive descriptor ring */
503
+	icplus_destroy_ring ( icp, &icp->rx );
504
+
505
+	/* Destroy transmit descriptor ring */
506
+	icplus_destroy_ring ( icp, &icp->tx );
507
+
508
+	/* Discard any unused receive buffers */
509
+	for ( i = 0 ; i < ICP_NUM_DESC ; i++ ) {
510
+		if ( icp->rx_iobuf[i] )
511
+			free_iob ( icp->rx_iobuf[i] );
512
+		icp->rx_iobuf[i] = NULL;
513
+	}
514
+}
515
+
516
+/**
517
+ * Transmit packet
518
+ *
519
+ * @v netdev		Network device
520
+ * @v iobuf		I/O buffer
521
+ * @ret rc		Return status code
522
+ */
523
+static int icplus_transmit ( struct net_device *netdev,
524
+			     struct io_buffer *iobuf ) {
525
+	struct icplus_nic *icp = netdev->priv;
526
+	struct icplus_descriptor *desc;
527
+	unsigned int tx_idx;
528
+	physaddr_t address;
529
+
530
+	/* Check if ring is full */
531
+	if ( ( icp->tx.prod - icp->tx.cons ) >= ICP_NUM_DESC ) {
532
+		DBGC ( icp, "ICP %p out of transmit descriptors\n", icp );
533
+		return -ENOBUFS;
534
+	}
535
+
536
+	/* Find TX descriptor entry to use */
537
+	tx_idx = ( icp->tx.prod++ % ICP_NUM_DESC );
538
+	desc = &icp->tx.entry[tx_idx];
539
+
540
+	/* Fill in TX descriptor */
541
+	address = virt_to_bus ( iobuf->data );
542
+	desc->data.address = cpu_to_le64 ( address );
543
+	desc->data.len = cpu_to_le16 ( iob_len ( iobuf ) );
544
+	wmb();
545
+	desc->control = ICP_TX_SOLE_FRAG;
546
+	wmb();
547
+
548
+	/* Ring doorbell */
549
+	writew ( ICP_DMACTRL_TXPOLLNOW, icp->regs + ICP_DMACTRL );
550
+
551
+	DBGC2 ( icp, "ICP %p TX %d is [%llx,%llx)\n", icp, tx_idx,
552
+		( ( unsigned long long ) address ),
553
+		( ( unsigned long long ) address + iob_len ( iobuf ) ) );
554
+	DBGC2_HDA ( icp, virt_to_phys ( desc ), desc, sizeof ( *desc ) );
555
+	return 0;
556
+}
557
+
558
+/**
559
+ * Poll for completed packets
560
+ *
561
+ * @v netdev		Network device
562
+ */
563
+static void icplus_poll_tx ( struct net_device *netdev ) {
564
+	struct icplus_nic *icp = netdev->priv;
565
+	struct icplus_descriptor *desc;
566
+	unsigned int tx_idx;
567
+
568
+	/* Check for completed packets */
569
+	while ( icp->tx.cons != icp->tx.prod ) {
570
+
571
+		/* Get next transmit descriptor */
572
+		tx_idx = ( icp->tx.cons % ICP_NUM_DESC );
573
+		desc = &icp->tx.entry[tx_idx];
574
+
575
+		/* Stop if descriptor is still in use */
576
+		if ( ! ( desc->control & ICP_DONE ) )
577
+			return;
578
+
579
+		/* Complete TX descriptor */
580
+		DBGC2 ( icp, "ICP %p TX %d complete\n", icp, tx_idx );
581
+		netdev_tx_complete_next ( netdev );
582
+		icp->tx.cons++;
583
+	}
584
+}
585
+
586
+/**
587
+ * Poll for received packets
588
+ *
589
+ * @v netdev		Network device
590
+ */
591
+static void icplus_poll_rx ( struct net_device *netdev ) {
592
+	struct icplus_nic *icp = netdev->priv;
593
+	struct icplus_descriptor *desc;
594
+	struct io_buffer *iobuf;
595
+	unsigned int rx_idx;
596
+	size_t len;
597
+
598
+	/* Check for received packets */
599
+	while ( icp->rx.cons != icp->rx.prod ) {
600
+
601
+		/* Get next transmit descriptor */
602
+		rx_idx = ( icp->rx.cons % ICP_NUM_DESC );
603
+		desc = &icp->rx.entry[rx_idx];
604
+
605
+		/* Stop if descriptor is still in use */
606
+		if ( ! ( desc->control & ICP_DONE ) )
607
+			return;
608
+
609
+		/* Populate I/O buffer */
610
+		iobuf = icp->rx_iobuf[rx_idx];
611
+		icp->rx_iobuf[rx_idx] = NULL;
612
+		len = le16_to_cpu ( desc->len );
613
+		iob_put ( iobuf, len );
614
+
615
+		/* Hand off to network stack */
616
+		if ( desc->flags & ( ICP_RX_ERR_OVERRUN | ICP_RX_ERR_RUNT |
617
+				     ICP_RX_ERR_ALIGN | ICP_RX_ERR_FCS |
618
+				     ICP_RX_ERR_OVERSIZED | ICP_RX_ERR_LEN ) ) {
619
+			DBGC ( icp, "ICP %p RX %d error (length %zd, "
620
+			       "flags %02x)\n", icp, rx_idx, len, desc->flags );
621
+			netdev_rx_err ( netdev, iobuf, -EIO );
622
+		} else {
623
+			DBGC2 ( icp, "ICP %p RX %d complete (length "
624
+				"%zd)\n", icp, rx_idx, len );
625
+			netdev_rx ( netdev, iobuf );
626
+		}
627
+		icp->rx.cons++;
628
+	}
629
+}
630
+
631
+/**
632
+ * Poll for completed and received packets
633
+ *
634
+ * @v netdev		Network device
635
+ */
636
+static void icplus_poll ( struct net_device *netdev ) {
637
+	struct icplus_nic *icp = netdev->priv;
638
+	uint16_t intstatus;
639
+	uint32_t txstatus;
640
+
641
+	/* Check for interrupts */
642
+	intstatus = readw ( icp->regs + ICP_INTSTATUS );
643
+
644
+	/* Poll for TX completions, if applicable */
645
+	if ( intstatus & ICP_INTSTATUS_TXCOMPLETE ) {
646
+		txstatus = readl ( icp->regs + ICP_TXSTATUS );
647
+		if ( txstatus & ICP_TXSTATUS_ERROR )
648
+			DBGC ( icp, "ICP %p TX error: %08x\n", icp, txstatus );
649
+		icplus_poll_tx ( netdev );
650
+	}
651
+
652
+	/* Poll for RX completions, if applicable */
653
+	if ( intstatus & ICP_INTSTATUS_RXDMACOMPLETE ) {
654
+		writew ( ICP_INTSTATUS_RXDMACOMPLETE, icp->regs + ICP_INTSTATUS );
655
+		icplus_poll_rx ( netdev );
656
+	}
657
+
658
+	/* Check link state, if applicable */
659
+	if ( intstatus & ICP_INTSTATUS_LINKEVENT ) {
660
+		writew ( ICP_INTSTATUS_LINKEVENT, icp->regs + ICP_INTSTATUS );
661
+		icplus_check_link ( netdev );
662
+	}
663
+
664
+	/* Refill receive ring */
665
+	icplus_refill_rx ( icp );
666
+}
667
+
668
+/**
669
+ * Enable or disable interrupts
670
+ *
671
+ * @v netdev		Network device
672
+ * @v enable		Interrupts should be enabled
673
+ */
674
+static void icplus_irq ( struct net_device *netdev, int enable ) {
675
+	struct icplus_nic *icp = netdev->priv;
676
+
677
+	DBGC ( icp, "ICPLUS %p does not yet support interrupts\n", icp );
678
+	( void ) enable;
679
+}
680
+
681
+/** IC+ network device operations */
682
+static struct net_device_operations icplus_operations = {
683
+	.open		= icplus_open,
684
+	.close		= icplus_close,
685
+	.transmit	= icplus_transmit,
686
+	.poll		= icplus_poll,
687
+	.irq		= icplus_irq,
688
+};
689
+
690
+/******************************************************************************
691
+ *
692
+ * PCI interface
693
+ *
694
+ ******************************************************************************
695
+ */
696
+
697
+/**
698
+ * Probe PCI device
699
+ *
700
+ * @v pci		PCI device
701
+ * @ret rc		Return status code
702
+ */
703
+static int icplus_probe ( struct pci_device *pci ) {
704
+	struct net_device *netdev;
705
+	struct icplus_nic *icp;
706
+	int rc;
707
+
708
+	/* Allocate and initialise net device */
709
+	netdev = alloc_etherdev ( sizeof ( *icp ) );
710
+	if ( ! netdev ) {
711
+		rc = -ENOMEM;
712
+		goto err_alloc;
713
+	}
714
+	netdev_init ( netdev, &icplus_operations );
715
+	icp = netdev->priv;
716
+	pci_set_drvdata ( pci, netdev );
717
+	netdev->dev = &pci->dev;
718
+	memset ( icp, 0, sizeof ( *icp ) );
719
+	icp->miibit.basher.op = &icplus_basher_ops;
720
+	init_mii_bit_basher ( &icp->miibit );
721
+	mii_init ( &icp->mii, &icp->miibit.mdio, 0 );
722
+	icp->tx.listptr = ICP_TFDLISTPTR;
723
+	icp->rx.listptr = ICP_RFDLISTPTR;
724
+
725
+	/* Fix up PCI device */
726
+	adjust_pci_device ( pci );
727
+
728
+	/* Map registers */
729
+	icp->regs = ioremap ( pci->membase, ICP_BAR_SIZE );
730
+	if ( ! icp->regs ) {
731
+		rc = -ENODEV;
732
+		goto err_ioremap;
733
+	}
734
+
735
+	/* Reset the NIC */
736
+	if ( ( rc = icplus_reset ( icp ) ) != 0 )
737
+		goto err_reset;
738
+
739
+	/* Initialise EEPROM */
740
+	icplus_init_eeprom ( icp );
741
+
742
+	/* Read EEPROM MAC address */
743
+	if ( ( rc = nvs_read ( &icp->eeprom, ICP_EEPROM_MAC,
744
+			       netdev->hw_addr, ETH_ALEN ) ) != 0 ) {
745
+		DBGC ( icp, "ICPLUS %p could not read EEPROM MAC address: %s\n",
746
+		       icp, strerror ( rc ) );
747
+		goto err_eeprom;
748
+	}
749
+
750
+	/* Configure PHY */
751
+	if ( ( rc = icplus_init_phy ( icp ) ) != 0 )
752
+		goto err_phy;
753
+
754
+	/* Register network device */
755
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
756
+		goto err_register_netdev;
757
+
758
+	/* Set initial link state */
759
+	icplus_check_link ( netdev );
760
+
761
+	return 0;
762
+
763
+	unregister_netdev ( netdev );
764
+ err_register_netdev:
765
+ err_phy:
766
+ err_eeprom:
767
+	icplus_reset ( icp );
768
+ err_reset:
769
+	iounmap ( icp->regs );
770
+ err_ioremap:
771
+	netdev_nullify ( netdev );
772
+	netdev_put ( netdev );
773
+ err_alloc:
774
+	return rc;
775
+}
776
+
777
+/**
778
+ * Remove PCI device
779
+ *
780
+ * @v pci		PCI device
781
+ */
782
+static void icplus_remove ( struct pci_device *pci ) {
783
+	struct net_device *netdev = pci_get_drvdata ( pci );
784
+	struct icplus_nic *icp = netdev->priv;
785
+
786
+	/* Unregister network device */
787
+	unregister_netdev ( netdev );
788
+
789
+	/* Reset card */
790
+	icplus_reset ( icp );
791
+
792
+	/* Free network device */
793
+	iounmap ( icp->regs );
794
+	netdev_nullify ( netdev );
795
+	netdev_put ( netdev );
796
+}
797
+
798
+/** IC+ PCI device IDs */
799
+static struct pci_device_id icplus_nics[] = {
800
+	PCI_ROM ( 0x13f0, 0x1023, "ip1000a",	"IP1000A", 0 ),
801
+};
802
+
803
+/** IC+ PCI driver */
804
+struct pci_driver icplus_driver __pci_driver = {
805
+	.ids = icplus_nics,
806
+	.id_count = ( sizeof ( icplus_nics ) / sizeof ( icplus_nics[0] ) ),
807
+	.probe = icplus_probe,
808
+	.remove = icplus_remove,
809
+};

+ 206
- 0
src/drivers/net/icplus.h View File

@@ -0,0 +1,206 @@
1
+#ifndef _ICPLUS_H
2
+#define _ICPLUS_H
3
+
4
+/** @file
5
+ *
6
+ * IC+ network driver
7
+ *
8
+ */
9
+
10
+#include <ipxe/nvs.h>
11
+#include <ipxe/mii_bit.h>
12
+
13
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
14
+
15
+/** BAR size */
16
+#define ICP_BAR_SIZE 0x200
17
+
18
+/** Alignment requirement */
19
+#define ICP_ALIGN 0x8
20
+
21
+/** Base address low register offset */
22
+#define ICP_BASE_LO 0x0
23
+
24
+/** Base address high register offset */
25
+#define ICP_BASE_HI 0x4
26
+
27
+/** ASIC control register (double word) */
28
+#define ICP_ASICCTRL 0x30
29
+#define ICP_ASICCTRL_PHYSPEED1000	0x00000040UL	/**< PHY speed 1000 */
30
+#define ICP_ASICCTRL_GLOBALRESET	0x00010000UL	/**< Global reset */
31
+#define ICP_ASICCTRL_DMA		0x00080000UL	/**< DMA */
32
+#define ICP_ASICCTRL_FIFO		0x00100000UL	/**< FIFO */
33
+#define ICP_ASICCTRL_NETWORK		0x00200000UL	/**< Network */
34
+#define ICP_ASICCTRL_HOST		0x00400000UL	/**< Host */
35
+#define ICP_ASICCTRL_AUTOINIT		0x00800000UL	/**< Auto init */
36
+#define ICP_ASICCTRL_RESETBUSY		0x04000000UL	/**< Reset busy */
37
+
38
+/** Maximum time to wait for reset */
39
+#define ICP_RESET_MAX_WAIT_MS 1000
40
+
41
+/** DMA control register (word/double word) */
42
+#define ICP_DMACTRL 0x00
43
+#define ICP_DMACTRL_RXPOLLNOW		0x0010		/**< Receive poll now */
44
+#define ICP_DMACTRL_TXPOLLNOW 		0x1000		/**< Transmit poll now */
45
+
46
+/** EEPROM control register (word) */
47
+#define ICP_EEPROMCTRL 0x4a
48
+#define ICP_EEPROMCTRL_ADDRESS( x )	( (x) << 0 )	/**< Address */
49
+#define ICP_EEPROMCTRL_OPCODE( x )	( (x) << 8 )	/**< Opcode */
50
+#define ICP_EEPROMCTRL_OPCODE_READ \
51
+	ICP_EEPROMCTRL_OPCODE ( 2 )			/**< Read register */
52
+#define ICP_EEPROMCTRL_BUSY		0x8000		/**< EEPROM busy */
53
+
54
+/** Maximum time to wait for reading EEPROM */
55
+#define ICP_EEPROM_MAX_WAIT_MS 1000
56
+
57
+/** EEPROM word length */
58
+#define ICP_EEPROM_WORD_LEN_LOG2 1
59
+
60
+/** Minimum EEPROM size, in words */
61
+#define ICP_EEPROM_MIN_SIZE_WORDS 0x20
62
+
63
+/** Address of MAC address within EEPROM */
64
+#define ICP_EEPROM_MAC 0x10
65
+
66
+/** EEPROM data register (word) */
67
+#define ICP_EEPROMDATA 0x48
68
+
69
+/** Interupt status register (word) */
70
+#define ICP_INTSTATUS 0x5e
71
+#define ICP_INTSTATUS_TXCOMPLETE	0x0004		/**< TX complete */
72
+#define ICP_INTSTATUS_LINKEVENT		0x0100		/**< Link event */
73
+#define ICP_INTSTATUS_RXDMACOMPLETE	0x0400		/**< RX DMA complete */
74
+
75
+/** MAC control register (double word) */
76
+#define ICP_MACCTRL 0x6c
77
+#define ICP_MACCTRL_DUPLEX		0x00000020UL	/**< Duplex select */
78
+#define ICP_MACCTRL_TXENABLE		0x01000000UL	/**< TX enable */
79
+#define ICP_MACCTRL_TXDISABLE		0x02000000UL	/**< TX disable */
80
+#define ICP_MACCTRL_RXENABLE		0x08000000UL	/**< RX enable */
81
+#define ICP_MACCTRL_RXDISABLE		0x10000000UL	/**< RX disable */
82
+
83
+/** PHY control register (byte) */
84
+#define ICP_PHYCTRL 0x76
85
+#define ICP_PHYCTRL_MGMTCLK		0x01		/**< Management clock */
86
+#define ICP_PHYCTRL_MGMTDATA		0x02		/**< Management data */
87
+#define ICP_PHYCTRL_MGMTDIR		0x04		/**< Management direction */
88
+#define ICP_PHYCTRL_LINKSPEED		0xc0		/**< Link speed */
89
+
90
+/** Receive mode register (word) */
91
+#define ICP_RXMODE 0x88
92
+#define ICP_RXMODE_UNICAST		0x0001		/**< Receive unicast */
93
+#define ICP_RXMODE_MULTICAST		0x0002		/**< Receice multicast */
94
+#define ICP_RXMODE_BROADCAST		0x0004		/**< Receive broadcast */
95
+#define ICP_RXMODE_ALLFRAMES		0x0008		/**< Receive all frames */
96
+
97
+/** List pointer receive register */
98
+#define ICP_RFDLISTPTR 0x1c
99
+
100
+/** List pointer transmit register */
101
+#define ICP_TFDLISTPTR 0x10
102
+
103
+/** Transmit status register */
104
+#define ICP_TXSTATUS 0x60
105
+#define ICP_TXSTATUS_ERROR		0x00000001UL	/**< TX error */
106
+
107
+/** Data fragment */
108
+union icplus_fragment {
109
+	/** Address of data */
110
+	uint64_t address;
111
+	/** Length */
112
+	struct {
113
+		/** Reserved */
114
+		uint8_t reserved[6];
115
+		/** Length of data */
116
+		uint16_t len;
117
+	};
118
+};
119
+
120
+/** Transmit or receive descriptor */
121
+struct icplus_descriptor {
122
+	/** Address of next descriptor */
123
+	uint64_t next;
124
+	/** Actual length */
125
+	uint16_t len;
126
+	/** Flags */
127
+	uint8_t flags;
128
+	/** Control */
129
+	uint8_t control;
130
+	/** VLAN */
131
+	uint16_t vlan;
132
+	/** Reserved */
133
+	uint16_t reserved_a;
134
+	/** Data buffer */
135
+	union icplus_fragment data;
136
+	/** Reserved */
137
+	uint8_t reserved_b[8];
138
+};
139
+
140
+/** Descriptor complete */
141
+#define ICP_DONE 0x80
142
+
143
+/** Transmit alignment disabled */
144
+#define ICP_TX_UNALIGN 0x01
145
+
146
+/** Request transmit completion */
147
+#define ICP_TX_INDICATE 0x40
148
+
149
+/** Sole transmit fragment */
150
+#define ICP_TX_SOLE_FRAG 0x01
151
+
152
+/** Recieve frame overrun error */
153
+#define ICP_RX_ERR_OVERRUN 0x01
154
+
155
+/** Receive runt frame error */
156
+#define ICP_RX_ERR_RUNT 0x02
157
+
158
+/** Receive alignment error */
159
+#define ICP_RX_ERR_ALIGN 0x04
160
+
161
+/** Receive FCS error */
162
+#define ICP_RX_ERR_FCS 0x08
163
+
164
+/** Receive oversized frame error */
165
+#define ICP_RX_ERR_OVERSIZED 0x10
166
+
167
+/** Recieve length error */
168
+#define ICP_RX_ERR_LEN 0x20
169
+
170
+/** Descriptor ring */
171
+struct icplus_ring {
172
+	/** Producer counter */
173
+	unsigned int prod;
174
+	/** Consumer counter */
175
+	unsigned int cons;
176
+	/** Ring entries */
177
+	struct icplus_descriptor *entry;
178
+	/* List pointer register */
179
+	unsigned int listptr;
180
+};
181
+
182
+/** Number of descriptors */
183
+#define ICP_NUM_DESC 4
184
+
185
+/** Maximum receive packet length */
186
+#define ICP_RX_MAX_LEN ETH_FRAME_LEN
187
+
188
+/** An IC+ network card */
189
+struct icplus_nic {
190
+	/** Registers */
191
+	void *regs;
192
+	/** EEPROM */
193
+	struct nvs_device eeprom;
194
+	/** MII bit bashing interface */
195
+	struct mii_bit_basher miibit;
196
+	/** MII device */
197
+	struct mii_device mii;
198
+	/** Transmit descriptor ring */
199
+	struct icplus_ring tx;
200
+	/** Receive descriptor ring */
201
+	struct icplus_ring rx;
202
+	/** Receive I/O buffers */
203
+	struct io_buffer *rx_iobuf[ICP_NUM_DESC];
204
+};
205
+
206
+#endif /* _ICPLUS_H */

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

@@ -203,6 +203,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
203 203
 #define ERRFILE_smscusb		     ( ERRFILE_DRIVER | 0x00c70000 )
204 204
 #define ERRFILE_lan78xx		     ( ERRFILE_DRIVER | 0x00c80000 )
205 205
 #define ERRFILE_ena		     ( ERRFILE_DRIVER | 0x00c90000 )
206
+#define ERRFILE_icplus		     ( ERRFILE_DRIVER | 0x00ca0000 )
206 207
 
207 208
 #define ERRFILE_aoe			( ERRFILE_NET | 0x00000000 )
208 209
 #define ERRFILE_arp			( ERRFILE_NET | 0x00010000 )

Loading…
Cancel
Save