|
@@ -1,596 +0,0 @@
|
1
|
|
-/* rtl8139.c - etherboot driver for the Realtek 8139 chipset
|
2
|
|
-
|
3
|
|
- ported from the linux driver written by Donald Becker
|
4
|
|
- by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999
|
5
|
|
-
|
6
|
|
- This software may be used and distributed according to the terms
|
7
|
|
- of the GNU Public License, incorporated herein by reference.
|
8
|
|
-
|
9
|
|
- changes to the original driver:
|
10
|
|
- - removed support for interrupts, switching to polling mode (yuck!)
|
11
|
|
- - removed support for the 8129 chip (external MII)
|
12
|
|
-
|
13
|
|
-*/
|
14
|
|
-
|
15
|
|
-FILE_LICENCE ( GPL_ANY );
|
16
|
|
-
|
17
|
|
-/*********************************************************************/
|
18
|
|
-/* Revision History */
|
19
|
|
-/*********************************************************************/
|
20
|
|
-
|
21
|
|
-/*
|
22
|
|
- 27 May 2006 mcb30@users.sourceforge.net (Michael Brown)
|
23
|
|
- Rewrote to use the new net driver API, the updated PCI API, and
|
24
|
|
- the generic three-wire serial device support for EEPROM access.
|
25
|
|
-
|
26
|
|
- 28 Dec 2002 ken_yap@users.sourceforge.net (Ken Yap)
|
27
|
|
- Put in virt_to_bus calls to allow Etherboot relocation.
|
28
|
|
-
|
29
|
|
- 06 Apr 2001 ken_yap@users.sourceforge.net (Ken Yap)
|
30
|
|
- Following email from Hyun-Joon Cha, added a disable routine, otherwise
|
31
|
|
- NIC remains live and can crash the kernel later.
|
32
|
|
-
|
33
|
|
- 4 Feb 2000 espenlaub@informatik.uni-ulm.de (Klaus Espenlaub)
|
34
|
|
- Shuffled things around, removed the leftovers from the 8129 support
|
35
|
|
- that was in the Linux driver and added a bit more 8139 definitions.
|
36
|
|
- Moved the 8K receive buffer to a fixed, available address outside the
|
37
|
|
- 0x98000-0x9ffff range. This is a bit of a hack, but currently the only
|
38
|
|
- way to make room for the Etherboot features that need substantial amounts
|
39
|
|
- of code like the ANSI console support. Currently the buffer is just below
|
40
|
|
- 0x10000, so this even conforms to the tagged boot image specification,
|
41
|
|
- which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000. My
|
42
|
|
- interpretation of this "reserved" is that Etherboot may do whatever it
|
43
|
|
- likes, as long as its environment is kept intact (like the BIOS
|
44
|
|
- variables). Hopefully fixed rtl_poll() once and for all. The symptoms
|
45
|
|
- were that if Etherboot was left at the boot menu for several minutes, the
|
46
|
|
- first eth_poll failed. Seems like I am the only person who does this.
|
47
|
|
- First of all I fixed the debugging code and then set out for a long bug
|
48
|
|
- hunting session. It took me about a week full time work - poking around
|
49
|
|
- various places in the driver, reading Don Becker's and Jeff Garzik's Linux
|
50
|
|
- driver and even the FreeBSD driver (what a piece of crap!) - and
|
51
|
|
- eventually spotted the nasty thing: the transmit routine was acknowledging
|
52
|
|
- each and every interrupt pending, including the RxOverrun and RxFIFIOver
|
53
|
|
- interrupts. This confused the RTL8139 thoroughly. It destroyed the
|
54
|
|
- Rx ring contents by dumping the 2K FIFO contents right where we wanted to
|
55
|
|
- get the next packet. Oh well, what fun.
|
56
|
|
-
|
57
|
|
- 18 Jan 2000 mdc@etherboot.org (Marty Connor)
|
58
|
|
- Drastically simplified error handling. Basically, if any error
|
59
|
|
- in transmission or reception occurs, the card is reset.
|
60
|
|
- Also, pointed all transmit descriptors to the same buffer to
|
61
|
|
- save buffer space. This should decrease driver size and avoid
|
62
|
|
- corruption because of exceeding 32K during runtime.
|
63
|
|
-
|
64
|
|
- 28 Jul 1999 (Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de)
|
65
|
|
- rtl_poll was quite broken: it used the RxOK interrupt flag instead
|
66
|
|
- of the RxBufferEmpty flag which often resulted in very bad
|
67
|
|
- transmission performace - below 1kBytes/s.
|
68
|
|
-
|
69
|
|
-*/
|
70
|
|
-
|
71
|
|
-#include <stdint.h>
|
72
|
|
-#include <stdlib.h>
|
73
|
|
-#include <stdio.h>
|
74
|
|
-#include <string.h>
|
75
|
|
-#include <ipxe/io.h>
|
76
|
|
-#include <errno.h>
|
77
|
|
-#include <unistd.h>
|
78
|
|
-#include <byteswap.h>
|
79
|
|
-#include <ipxe/pci.h>
|
80
|
|
-#include <ipxe/if_ether.h>
|
81
|
|
-#include <ipxe/ethernet.h>
|
82
|
|
-#include <ipxe/iobuf.h>
|
83
|
|
-#include <ipxe/netdevice.h>
|
84
|
|
-#include <ipxe/spi_bit.h>
|
85
|
|
-#include <ipxe/threewire.h>
|
86
|
|
-#include <ipxe/nvo.h>
|
87
|
|
-
|
88
|
|
-#define TX_RING_SIZE 4
|
89
|
|
-#define TX_MAX_LEN 8192
|
90
|
|
-
|
91
|
|
-struct rtl8139_tx {
|
92
|
|
- unsigned int next;
|
93
|
|
- struct io_buffer *iobuf[TX_RING_SIZE];
|
94
|
|
-};
|
95
|
|
-
|
96
|
|
-struct rtl8139_rx {
|
97
|
|
- void *ring;
|
98
|
|
- unsigned int offset;
|
99
|
|
-};
|
100
|
|
-
|
101
|
|
-struct rtl8139_nic {
|
102
|
|
- unsigned short ioaddr;
|
103
|
|
- struct rtl8139_tx tx;
|
104
|
|
- struct rtl8139_rx rx;
|
105
|
|
- struct spi_bit_basher spibit;
|
106
|
|
- struct spi_device eeprom;
|
107
|
|
- struct nvo_block nvo;
|
108
|
|
-};
|
109
|
|
-
|
110
|
|
-/* Tuning Parameters */
|
111
|
|
-#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
|
112
|
|
-#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
|
113
|
|
-#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
|
114
|
|
-#define TX_DMA_BURST 4 /* Calculate as 16<<val. */
|
115
|
|
-#define TX_IPG 3 /* This is the only valid value */
|
116
|
|
-#define RX_BUF_LEN_IDX 0 /* 0, 1, 2 is allowed - 8,16,32K rx buffer */
|
117
|
|
-#define RX_BUF_LEN ( (8192 << RX_BUF_LEN_IDX) )
|
118
|
|
-#define RX_BUF_PAD 4
|
119
|
|
-
|
120
|
|
-/* Symbolic offsets to registers. */
|
121
|
|
-enum RTL8139_registers {
|
122
|
|
- MAC0=0, /* Ethernet hardware address. */
|
123
|
|
- MAR0=8, /* Multicast filter. */
|
124
|
|
- TxStatus0=0x10, /* Transmit status (four 32bit registers). */
|
125
|
|
- TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
|
126
|
|
- RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
|
127
|
|
- ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
|
128
|
|
- IntrMask=0x3C, IntrStatus=0x3E,
|
129
|
|
- TxConfig=0x40, RxConfig=0x44,
|
130
|
|
- Timer=0x48, /* general-purpose counter. */
|
131
|
|
- RxMissed=0x4C, /* 24 bits valid, write clears. */
|
132
|
|
- Cfg9346=0x50, Config0=0x51, Config1=0x52,
|
133
|
|
- TimerIntrReg=0x54, /* intr if gp counter reaches this value */
|
134
|
|
- MediaStatus=0x58,
|
135
|
|
- Config3=0x59,
|
136
|
|
- MultiIntr=0x5C,
|
137
|
|
- RevisionID=0x5E, /* revision of the RTL8139 chip */
|
138
|
|
- TxSummary=0x60,
|
139
|
|
- MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
|
140
|
|
- NWayExpansion=0x6A,
|
141
|
|
- DisconnectCnt=0x6C, FalseCarrierCnt=0x6E,
|
142
|
|
- NWayTestReg=0x70,
|
143
|
|
- RxCnt=0x72, /* packet received counter */
|
144
|
|
- CSCR=0x74, /* chip status and configuration register */
|
145
|
|
- PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80, /* undocumented */
|
146
|
|
- /* from 0x84 onwards are a number of power management/wakeup frame
|
147
|
|
- * definitions we will probably never need to know about. */
|
148
|
|
-};
|
149
|
|
-
|
150
|
|
-enum RxEarlyStatusBits {
|
151
|
|
- ERGood=0x08, ERBad=0x04, EROVW=0x02, EROK=0x01
|
152
|
|
-};
|
153
|
|
-
|
154
|
|
-enum ChipCmdBits {
|
155
|
|
- CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
|
156
|
|
-
|
157
|
|
-enum IntrMaskBits {
|
158
|
|
- SERR=0x8000, TimeOut=0x4000, LenChg=0x2000,
|
159
|
|
- FOVW=0x40, PUN_LinkChg=0x20, RXOVW=0x10,
|
160
|
|
- TER=0x08, TOK=0x04, RER=0x02, ROK=0x01
|
161
|
|
-};
|
162
|
|
-
|
163
|
|
-/* Interrupt register bits, using my own meaningful names. */
|
164
|
|
-enum IntrStatusBits {
|
165
|
|
- PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000,
|
166
|
|
- RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
|
167
|
|
- TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
|
168
|
|
-};
|
169
|
|
-enum TxStatusBits {
|
170
|
|
- TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
|
171
|
|
- TxOutOfWindow=0x20000000, TxAborted=0x40000000,
|
172
|
|
- TxCarrierLost=0x80000000,
|
173
|
|
-};
|
174
|
|
-enum RxStatusBits {
|
175
|
|
- RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
|
176
|
|
- RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
|
177
|
|
- RxBadAlign=0x0002, RxStatusOK=0x0001,
|
178
|
|
-};
|
179
|
|
-
|
180
|
|
-enum MediaStatusBits {
|
181
|
|
- MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08,
|
182
|
|
- MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01,
|
183
|
|
-};
|
184
|
|
-
|
185
|
|
-enum MIIBMCRBits {
|
186
|
|
- BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000,
|
187
|
|
- BMCRRestartNWay=0x0200, BMCRDuplex=0x0100,
|
188
|
|
-};
|
189
|
|
-
|
190
|
|
-enum CSCRBits {
|
191
|
|
- CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
|
192
|
|
- CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
|
193
|
|
- CSCR_LinkDownCmd=0x0f3c0,
|
194
|
|
-};
|
195
|
|
-
|
196
|
|
-enum RxConfigBits {
|
197
|
|
- RxCfgWrap=0x80,
|
198
|
|
- Eeprom9356=0x40,
|
199
|
|
- AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
|
200
|
|
- AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
|
201
|
|
-};
|
202
|
|
-
|
203
|
|
-enum Config1Bits {
|
204
|
|
- VPDEnable=0x02,
|
205
|
|
-};
|
206
|
|
-
|
207
|
|
-/* EEPROM access */
|
208
|
|
-#define EE_M1 0x80 /* Mode select bit 1 */
|
209
|
|
-#define EE_M0 0x40 /* Mode select bit 0 */
|
210
|
|
-#define EE_CS 0x08 /* EEPROM chip select */
|
211
|
|
-#define EE_SK 0x04 /* EEPROM shift clock */
|
212
|
|
-#define EE_DI 0x02 /* Data in */
|
213
|
|
-#define EE_DO 0x01 /* Data out */
|
214
|
|
-
|
215
|
|
-/* Offsets within EEPROM (these are word offsets) */
|
216
|
|
-#define EE_MAC 7
|
217
|
|
-
|
218
|
|
-static const uint8_t rtl_ee_bits[] = {
|
219
|
|
- [SPI_BIT_SCLK] = EE_SK,
|
220
|
|
- [SPI_BIT_MOSI] = EE_DI,
|
221
|
|
- [SPI_BIT_MISO] = EE_DO,
|
222
|
|
- [SPI_BIT_SS(0)] = ( EE_CS | EE_M1 ),
|
223
|
|
-};
|
224
|
|
-
|
225
|
|
-static int rtl_spi_read_bit ( struct bit_basher *basher,
|
226
|
|
- unsigned int bit_id ) {
|
227
|
|
- struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic,
|
228
|
|
- spibit.basher );
|
229
|
|
- uint8_t mask = rtl_ee_bits[bit_id];
|
230
|
|
- uint8_t eereg;
|
231
|
|
-
|
232
|
|
- eereg = inb ( rtl->ioaddr + Cfg9346 );
|
233
|
|
- return ( eereg & mask );
|
234
|
|
-}
|
235
|
|
-
|
236
|
|
-static void rtl_spi_write_bit ( struct bit_basher *basher,
|
237
|
|
- unsigned int bit_id, unsigned long data ) {
|
238
|
|
- struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic,
|
239
|
|
- spibit.basher );
|
240
|
|
- uint8_t mask = rtl_ee_bits[bit_id];
|
241
|
|
- uint8_t eereg;
|
242
|
|
-
|
243
|
|
- eereg = inb ( rtl->ioaddr + Cfg9346 );
|
244
|
|
- eereg &= ~mask;
|
245
|
|
- eereg |= ( data & mask );
|
246
|
|
- outb ( eereg, rtl->ioaddr + Cfg9346 );
|
247
|
|
-}
|
248
|
|
-
|
249
|
|
-static struct bit_basher_operations rtl_basher_ops = {
|
250
|
|
- .read = rtl_spi_read_bit,
|
251
|
|
- .write = rtl_spi_write_bit,
|
252
|
|
-};
|
253
|
|
-
|
254
|
|
-/**
|
255
|
|
- * Set up for EEPROM access
|
256
|
|
- *
|
257
|
|
- * @v netdev Net device
|
258
|
|
- */
|
259
|
|
-static void rtl_init_eeprom ( struct net_device *netdev ) {
|
260
|
|
- struct rtl8139_nic *rtl = netdev->priv;
|
261
|
|
- int ee9356;
|
262
|
|
- int vpd;
|
263
|
|
-
|
264
|
|
- /* Initialise three-wire bus */
|
265
|
|
- rtl->spibit.basher.op = &rtl_basher_ops;
|
266
|
|
- rtl->spibit.bus.mode = SPI_MODE_THREEWIRE;
|
267
|
|
- init_spi_bit_basher ( &rtl->spibit );
|
268
|
|
-
|
269
|
|
- /* Detect EEPROM type and initialise three-wire device */
|
270
|
|
- ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 );
|
271
|
|
- if ( ee9356 ) {
|
272
|
|
- DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C56\n", rtl );
|
273
|
|
- init_at93c56 ( &rtl->eeprom, 16 );
|
274
|
|
- } else {
|
275
|
|
- DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C46\n", rtl );
|
276
|
|
- init_at93c46 ( &rtl->eeprom, 16 );
|
277
|
|
- }
|
278
|
|
- rtl->eeprom.bus = &rtl->spibit.bus;
|
279
|
|
-
|
280
|
|
- /* Initialise space for non-volatile options, if available
|
281
|
|
- *
|
282
|
|
- * We use offset 0x40 (i.e. address 0x20), length 0x40. This
|
283
|
|
- * block is marked as VPD in the rtl8139 datasheets, so we use
|
284
|
|
- * it only if we detect that the card is not supporting VPD.
|
285
|
|
- */
|
286
|
|
- vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable );
|
287
|
|
- if ( vpd ) {
|
288
|
|
- DBGC ( rtl, "rtl8139 %p EEPROM in use for VPD; cannot use "
|
289
|
|
- "for options\n", rtl );
|
290
|
|
- } else {
|
291
|
|
- nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, 0x20, 0x40, NULL,
|
292
|
|
- &netdev->refcnt );
|
293
|
|
- }
|
294
|
|
-}
|
295
|
|
-
|
296
|
|
-/**
|
297
|
|
- * Reset NIC
|
298
|
|
- *
|
299
|
|
- * @v netdev Net device
|
300
|
|
- *
|
301
|
|
- * Issues a hardware reset and waits for the reset to complete.
|
302
|
|
- */
|
303
|
|
-static void rtl_reset ( struct net_device *netdev ) {
|
304
|
|
- struct rtl8139_nic *rtl = netdev->priv;
|
305
|
|
-
|
306
|
|
- /* Reset chip */
|
307
|
|
- outb ( CmdReset, rtl->ioaddr + ChipCmd );
|
308
|
|
- mdelay ( 10 );
|
309
|
|
- memset ( &rtl->tx, 0, sizeof ( rtl->tx ) );
|
310
|
|
- rtl->rx.offset = 0;
|
311
|
|
-}
|
312
|
|
-
|
313
|
|
-/**
|
314
|
|
- * Open NIC
|
315
|
|
- *
|
316
|
|
- * @v netdev Net device
|
317
|
|
- * @ret rc Return status code
|
318
|
|
- */
|
319
|
|
-static int rtl_open ( struct net_device *netdev ) {
|
320
|
|
- struct rtl8139_nic *rtl = netdev->priv;
|
321
|
|
- int i;
|
322
|
|
-
|
323
|
|
- /* Program the MAC address */
|
324
|
|
- for ( i = 0 ; i < ETH_ALEN ; i++ )
|
325
|
|
- outb ( netdev->ll_addr[i], rtl->ioaddr + MAC0 + i );
|
326
|
|
-
|
327
|
|
- /* Set up RX ring */
|
328
|
|
- rtl->rx.ring = malloc ( RX_BUF_LEN + RX_BUF_PAD );
|
329
|
|
- if ( ! rtl->rx.ring )
|
330
|
|
- return -ENOMEM;
|
331
|
|
- outl ( virt_to_bus ( rtl->rx.ring ), rtl->ioaddr + RxBuf );
|
332
|
|
- DBGC ( rtl, "rtl8139 %p RX ring at %lx\n",
|
333
|
|
- rtl, virt_to_bus ( rtl->rx.ring ) );
|
334
|
|
-
|
335
|
|
- /* Enable TX and RX */
|
336
|
|
- outb ( ( CmdRxEnb | CmdTxEnb ), rtl->ioaddr + ChipCmd );
|
337
|
|
- outl ( ( ( RX_FIFO_THRESH << 13 ) | ( RX_BUF_LEN_IDX << 11 ) |
|
338
|
|
- ( RX_DMA_BURST << 8 ) | AcceptBroadcast | AcceptMulticast |
|
339
|
|
- AcceptMyPhys | AcceptAllPhys ), rtl->ioaddr + RxConfig );
|
340
|
|
- outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 0 );
|
341
|
|
- outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 4 );
|
342
|
|
- outl ( ( ( TX_DMA_BURST << 8 ) | ( TX_IPG << 24 ) ),
|
343
|
|
- rtl->ioaddr + TxConfig );
|
344
|
|
-
|
345
|
|
- return 0;
|
346
|
|
-}
|
347
|
|
-
|
348
|
|
-/**
|
349
|
|
- * Close NIC
|
350
|
|
- *
|
351
|
|
- * @v netdev Net device
|
352
|
|
- */
|
353
|
|
-static void rtl_close ( struct net_device *netdev ) {
|
354
|
|
- struct rtl8139_nic *rtl = netdev->priv;
|
355
|
|
-
|
356
|
|
- /* Reset the hardware to disable everything in one go */
|
357
|
|
- rtl_reset ( netdev );
|
358
|
|
-
|
359
|
|
- /* Free RX ring */
|
360
|
|
- free ( rtl->rx.ring );
|
361
|
|
- rtl->rx.ring = NULL;
|
362
|
|
-}
|
363
|
|
-
|
364
|
|
-/**
|
365
|
|
- * Transmit packet
|
366
|
|
- *
|
367
|
|
- * @v netdev Network device
|
368
|
|
- * @v iobuf I/O buffer
|
369
|
|
- * @ret rc Return status code
|
370
|
|
- */
|
371
|
|
-static int rtl_transmit ( struct net_device *netdev,
|
372
|
|
- struct io_buffer *iobuf ) {
|
373
|
|
- struct rtl8139_nic *rtl = netdev->priv;
|
374
|
|
-
|
375
|
|
- /* Check for space in TX ring */
|
376
|
|
- if ( rtl->tx.iobuf[rtl->tx.next] != NULL ) {
|
377
|
|
- DBGC ( rtl, "rtl8139 %p TX overflow\n", rtl );
|
378
|
|
- return -ENOBUFS;
|
379
|
|
- }
|
380
|
|
-
|
381
|
|
- /* Check for oversized packets */
|
382
|
|
- if ( iob_len ( iobuf ) >= TX_MAX_LEN ) {
|
383
|
|
- DBGC ( rtl, "rtl8139 %p TX too large (%zd bytes)\n",
|
384
|
|
- rtl, iob_len ( iobuf ) );
|
385
|
|
- return -ERANGE;
|
386
|
|
- }
|
387
|
|
-
|
388
|
|
- /* Pad and align packet */
|
389
|
|
- iob_pad ( iobuf, ETH_ZLEN );
|
390
|
|
-
|
391
|
|
- /* Add to TX ring */
|
392
|
|
- DBGC2 ( rtl, "rtl8139 %p TX id %d at %lx+%zx\n", rtl, rtl->tx.next,
|
393
|
|
- virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
|
394
|
|
- rtl->tx.iobuf[rtl->tx.next] = iobuf;
|
395
|
|
- outl ( virt_to_bus ( iobuf->data ),
|
396
|
|
- rtl->ioaddr + TxAddr0 + 4 * rtl->tx.next );
|
397
|
|
- outl ( ( ( ( TX_FIFO_THRESH & 0x7e0 ) << 11 ) | iob_len ( iobuf ) ),
|
398
|
|
- rtl->ioaddr + TxStatus0 + 4 * rtl->tx.next );
|
399
|
|
- rtl->tx.next = ( rtl->tx.next + 1 ) % TX_RING_SIZE;
|
400
|
|
-
|
401
|
|
- return 0;
|
402
|
|
-}
|
403
|
|
-
|
404
|
|
-/**
|
405
|
|
- * Poll for received packets
|
406
|
|
- *
|
407
|
|
- * @v netdev Network device
|
408
|
|
- */
|
409
|
|
-static void rtl_poll ( struct net_device *netdev ) {
|
410
|
|
- struct rtl8139_nic *rtl = netdev->priv;
|
411
|
|
- unsigned int status;
|
412
|
|
- unsigned int tsad;
|
413
|
|
- unsigned int rx_status;
|
414
|
|
- unsigned int rx_len;
|
415
|
|
- struct io_buffer *rx_iob;
|
416
|
|
- int wrapped_len;
|
417
|
|
- int i;
|
418
|
|
-
|
419
|
|
- /* Acknowledge interrupts */
|
420
|
|
- status = inw ( rtl->ioaddr + IntrStatus );
|
421
|
|
- if ( ! status )
|
422
|
|
- return;
|
423
|
|
- outw ( status, rtl->ioaddr + IntrStatus );
|
424
|
|
-
|
425
|
|
- /* Handle TX completions */
|
426
|
|
- tsad = inw ( rtl->ioaddr + TxSummary );
|
427
|
|
- for ( i = 0 ; i < TX_RING_SIZE ; i++ ) {
|
428
|
|
- if ( ( rtl->tx.iobuf[i] != NULL ) && ( tsad & ( 1 << i ) ) ) {
|
429
|
|
- DBGC2 ( rtl, "rtl8139 %p TX id %d complete\n",
|
430
|
|
- rtl, i );
|
431
|
|
- netdev_tx_complete ( netdev, rtl->tx.iobuf[i] );
|
432
|
|
- rtl->tx.iobuf[i] = NULL;
|
433
|
|
- }
|
434
|
|
- }
|
435
|
|
-
|
436
|
|
- /* Handle received packets */
|
437
|
|
- while ( ! ( inb ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ) {
|
438
|
|
- rx_status = * ( ( uint16_t * )
|
439
|
|
- ( rtl->rx.ring + rtl->rx.offset ) );
|
440
|
|
- rx_len = * ( ( uint16_t * )
|
441
|
|
- ( rtl->rx.ring + rtl->rx.offset + 2 ) );
|
442
|
|
- if ( rx_status & RxOK ) {
|
443
|
|
- DBGC2 ( rtl, "rtl8139 %p RX packet at offset "
|
444
|
|
- "%x+%x\n", rtl, rtl->rx.offset, rx_len );
|
445
|
|
-
|
446
|
|
- rx_iob = alloc_iob ( rx_len );
|
447
|
|
- if ( ! rx_iob ) {
|
448
|
|
- netdev_rx_err ( netdev, NULL, -ENOMEM );
|
449
|
|
- /* Leave packet for next call to poll() */
|
450
|
|
- break;
|
451
|
|
- }
|
452
|
|
-
|
453
|
|
- wrapped_len = ( ( rtl->rx.offset + 4 + rx_len )
|
454
|
|
- - RX_BUF_LEN );
|
455
|
|
- if ( wrapped_len < 0 )
|
456
|
|
- wrapped_len = 0;
|
457
|
|
-
|
458
|
|
- memcpy ( iob_put ( rx_iob, rx_len - wrapped_len ),
|
459
|
|
- rtl->rx.ring + rtl->rx.offset + 4,
|
460
|
|
- rx_len - wrapped_len );
|
461
|
|
- memcpy ( iob_put ( rx_iob, wrapped_len ),
|
462
|
|
- rtl->rx.ring, wrapped_len );
|
463
|
|
- iob_unput ( rx_iob, 4 ); /* Strip CRC */
|
464
|
|
-
|
465
|
|
- netdev_rx ( netdev, rx_iob );
|
466
|
|
- } else {
|
467
|
|
- DBGC ( rtl, "rtl8139 %p RX bad packet (status %#04x "
|
468
|
|
- "len %d)\n", rtl, rx_status, rx_len );
|
469
|
|
- netdev_rx_err ( netdev, NULL, -EINVAL );
|
470
|
|
- }
|
471
|
|
- rtl->rx.offset = ( ( ( rtl->rx.offset + 4 + rx_len + 3 ) & ~3 )
|
472
|
|
- % RX_BUF_LEN );
|
473
|
|
- outw ( rtl->rx.offset - 16, rtl->ioaddr + RxBufPtr );
|
474
|
|
- }
|
475
|
|
-}
|
476
|
|
-
|
477
|
|
-/**
|
478
|
|
- * Enable/disable interrupts
|
479
|
|
- *
|
480
|
|
- * @v netdev Network device
|
481
|
|
- * @v enable Interrupts should be enabled
|
482
|
|
- */
|
483
|
|
-static void rtl_irq ( struct net_device *netdev, int enable ) {
|
484
|
|
- struct rtl8139_nic *rtl = netdev->priv;
|
485
|
|
-
|
486
|
|
- DBGC ( rtl, "rtl8139 %p interrupts %s\n",
|
487
|
|
- rtl, ( enable ? "enabled" : "disabled" ) );
|
488
|
|
- outw ( ( enable ? ( ROK | RER | TOK | TER ) : 0 ),
|
489
|
|
- rtl->ioaddr + IntrMask );
|
490
|
|
-}
|
491
|
|
-
|
492
|
|
-/** RTL8139 net device operations */
|
493
|
|
-static struct net_device_operations rtl_operations = {
|
494
|
|
- .open = rtl_open,
|
495
|
|
- .close = rtl_close,
|
496
|
|
- .transmit = rtl_transmit,
|
497
|
|
- .poll = rtl_poll,
|
498
|
|
- .irq = rtl_irq,
|
499
|
|
-};
|
500
|
|
-
|
501
|
|
-/**
|
502
|
|
- * Probe PCI device
|
503
|
|
- *
|
504
|
|
- * @v pci PCI device
|
505
|
|
- * @v id PCI ID
|
506
|
|
- * @ret rc Return status code
|
507
|
|
- */
|
508
|
|
-static int rtl_probe ( struct pci_device *pci ) {
|
509
|
|
- struct net_device *netdev;
|
510
|
|
- struct rtl8139_nic *rtl;
|
511
|
|
- int rc;
|
512
|
|
-
|
513
|
|
- /* Allocate net device */
|
514
|
|
- netdev = alloc_etherdev ( sizeof ( *rtl ) );
|
515
|
|
- if ( ! netdev )
|
516
|
|
- return -ENOMEM;
|
517
|
|
- netdev_init ( netdev, &rtl_operations );
|
518
|
|
- rtl = netdev->priv;
|
519
|
|
- pci_set_drvdata ( pci, netdev );
|
520
|
|
- netdev->dev = &pci->dev;
|
521
|
|
- memset ( rtl, 0, sizeof ( *rtl ) );
|
522
|
|
- rtl->ioaddr = pci->ioaddr;
|
523
|
|
-
|
524
|
|
- /* Fix up PCI device */
|
525
|
|
- adjust_pci_device ( pci );
|
526
|
|
-
|
527
|
|
- /* Reset the NIC, set up EEPROM access and read MAC address */
|
528
|
|
- rtl_reset ( netdev );
|
529
|
|
- rtl_init_eeprom ( netdev );
|
530
|
|
- nvs_read ( &rtl->eeprom.nvs, EE_MAC, netdev->hw_addr, ETH_ALEN );
|
531
|
|
-
|
532
|
|
- /* Register network device */
|
533
|
|
- if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
534
|
|
- goto err_register_netdev;
|
535
|
|
-
|
536
|
|
- /* Mark as link up; we don't yet handle link state */
|
537
|
|
- netdev_link_up ( netdev );
|
538
|
|
-
|
539
|
|
- /* Register non-volatile storage */
|
540
|
|
- if ( rtl->nvo.nvs ) {
|
541
|
|
- if ( ( rc = register_nvo ( &rtl->nvo,
|
542
|
|
- netdev_settings ( netdev ) ) ) != 0)
|
543
|
|
- goto err_register_nvo;
|
544
|
|
- }
|
545
|
|
-
|
546
|
|
- return 0;
|
547
|
|
-
|
548
|
|
- err_register_nvo:
|
549
|
|
- unregister_netdev ( netdev );
|
550
|
|
- err_register_netdev:
|
551
|
|
- rtl_reset ( netdev );
|
552
|
|
- netdev_nullify ( netdev );
|
553
|
|
- netdev_put ( netdev );
|
554
|
|
- return rc;
|
555
|
|
-}
|
556
|
|
-
|
557
|
|
-/**
|
558
|
|
- * Remove PCI device
|
559
|
|
- *
|
560
|
|
- * @v pci PCI device
|
561
|
|
- */
|
562
|
|
-static void rtl_remove ( struct pci_device *pci ) {
|
563
|
|
- struct net_device *netdev = pci_get_drvdata ( pci );
|
564
|
|
- struct rtl8139_nic *rtl = netdev->priv;
|
565
|
|
-
|
566
|
|
- if ( rtl->nvo.nvs )
|
567
|
|
- unregister_nvo ( &rtl->nvo );
|
568
|
|
- unregister_netdev ( netdev );
|
569
|
|
- rtl_reset ( netdev );
|
570
|
|
- netdev_nullify ( netdev );
|
571
|
|
- netdev_put ( netdev );
|
572
|
|
-}
|
573
|
|
-
|
574
|
|
-static struct pci_device_id rtl8139_nics[] = {
|
575
|
|
-PCI_ROM(0x10ec, 0x8129, "rtl8129", "Realtek 8129", 0),
|
576
|
|
-PCI_ROM(0x10ec, 0x8139, "rtl8139", "Realtek 8139", 0),
|
577
|
|
-PCI_ROM(0x10ec, 0x8138, "rtl8139b", "Realtek 8139B", 0),
|
578
|
|
-PCI_ROM(0x1186, 0x1300, "dfe538", "DFE530TX+/DFE538TX", 0),
|
579
|
|
-PCI_ROM(0x1113, 0x1211, "smc1211-1", "SMC EZ10/100", 0),
|
580
|
|
-PCI_ROM(0x1112, 0x1211, "smc1211", "SMC EZ10/100", 0),
|
581
|
|
-PCI_ROM(0x1500, 0x1360, "delta8139", "Delta Electronics 8139", 0),
|
582
|
|
-PCI_ROM(0x4033, 0x1360, "addtron8139", "Addtron Technology 8139", 0),
|
583
|
|
-PCI_ROM(0x1186, 0x1340, "dfe690txd", "D-Link DFE690TXD", 0),
|
584
|
|
-PCI_ROM(0x13d1, 0xab06, "fe2000vx", "AboCom FE2000VX", 0),
|
585
|
|
-PCI_ROM(0x1259, 0xa117, "allied8139", "Allied Telesyn 8139", 0),
|
586
|
|
-PCI_ROM(0x14ea, 0xab06, "fnw3603tx", "Planex FNW-3603-TX", 0),
|
587
|
|
-PCI_ROM(0x14ea, 0xab07, "fnw3800tx", "Planex FNW-3800-TX", 0),
|
588
|
|
-PCI_ROM(0xffff, 0x8139, "clone-rtl8139", "Cloned 8139", 0),
|
589
|
|
-};
|
590
|
|
-
|
591
|
|
-struct pci_driver rtl8139_driver __pci_driver = {
|
592
|
|
- .ids = rtl8139_nics,
|
593
|
|
- .id_count = ( sizeof ( rtl8139_nics ) / sizeof ( rtl8139_nics[0] ) ),
|
594
|
|
- .probe = rtl_probe,
|
595
|
|
- .remove = rtl_remove,
|
596
|
|
-};
|