/[pearpc]/src/io/rtl8139/rtl8139.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/io/rtl8139/rtl8139.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 22082 byte(s)
import upstream CVS
1 /*
2 * PearPC
3 * rtl8139.cc
4 *
5 * RealTek 8139 Emulation
6 * References:
7 * [1] pearpc 3c90x driver
8 * [2] Linux Kernel 2.4.22 (drivers/net/rtl8139.c)
9 * [3] realtek 8139 technical specification/programming guide
10 *
11 * Copyright (C) 2004 John Kelley (pearpc@kelley.ca)
12 * Copyright (C) 2003 Stefan Weyergraf
13 * Copyright (C) 2004 Eric Estabrooks (estabroo2battlefoundry.net)
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License version 2 as
17 * published by the Free Software Foundation.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 *
28 * FIXME: Implement EthTunDriver write frame prefixing
29 */
30
31 #include <cerrno>
32 #include <cstdlib>
33 #include <cstring>
34 #include <unistd.h>
35
36 #include "system/sys.h"
37 #include "system/systhread.h"
38 #include "system/arch/sysendian.h"
39 #include "cpu/mem.h"
40 #include "cpu/debug.h"
41 #include "system/sysethtun.h"
42 #include "tools/crc32.h"
43 #include "tools/data.h"
44 #include "tools/debug.h"
45 #include "tools/except.h"
46 #include "tools/snprintf.h"
47 #include "io/pic/pic.h"
48 #include "io/pci/pci.h"
49 #include "debug/tracers.h"
50 #include "rtl8139.h"
51
52 #define MAX_PACKET_SIZE 6000
53 #define MAX_PACKETS 128
54
55
56 enum RxHeaderBits {
57 Rx_ROK = 1<<0, // receive okay
58 Rx_FAE = 1<<1, // frame alignment error
59 Rx_CRC = 1<<2, // crc error
60 Rx_LONG = 1<<3, // packet > 4k
61 Rx_RUNT = 1<<4, // packet < 64 bytes
62 Rx_ISE = 1<<5, // invalid symbol error
63 /* bits 6-12 reserved */
64 Rx_BAR = 1<<13, // broadcast
65 Rx_PAM = 1<<14, // exact match
66 Rx_MAR = 1<<15, // multicast
67 };
68
69 enum RxConfigurationBits {
70 Rx_RBLEN = 3<<11,
71 };
72
73 /* registers */
74 struct Registers {
75 uint8 id0; // 0x00 (mac address)
76 uint8 id1;
77 uint8 id2;
78 uint8 id3;
79 uint8 id4;
80 uint8 id5;
81 uint16 rsvd0; // 0x06-0x07
82 uint8 mar0;
83 uint8 mar1;
84 uint8 mar2;
85 uint8 mar3;
86 uint8 mar4;
87 uint8 mar5;
88 uint8 mar6;
89 uint8 mar7;
90 uint32 TxStatusD0; // 0x10
91 uint32 TxStatusD1; // 0x14
92 uint32 TxStatusD2; // 0x18
93 uint32 TxStatusD3; // 0x1c
94 uint32 TxStartAddrD0; // 0x20
95 uint32 TxStartAddrD1; // 0x24
96 uint32 TxStartAddrD2; // 0x28
97 uint32 TxStartAddrD3; // 0x2c
98 uint32 RxBufferStartAddr; // 0x30
99 uint16 EarlyRxByteCount; // 0x34
100 uint8 EarlyRxStatus; // 0x36
101 uint8 CommandRegister; // 0x37
102 uint16 CAPR; // 0x38 initial 0xfff0
103 uint16 CBA; // 0x3a initial 0x0000
104 uint16 InterruptMask; // 0x3c
105 uint16 InterruptStatus; // 0x3e
106 uint32 TxConfiguration; // 0x40
107 uint32 RxConfiguration; // 0x44
108 uint32 TimerCount; // 0x48
109 uint32 MissedPacketCounter; // 0x4c
110 uint8 Command93C46; //0x50
111 uint8 Config0; // 0x51
112 uint8 Config1; // 0x52
113 uint8 rsvd1 ; // 0x53
114 uint32 TimerInterrupt; // 0x54
115 uint8 MediaStatus; // 0x58
116 uint8 Config3; // 0x59
117 uint8 Config4; // 0x5a
118 uint8 rsvd2; // 0x5b
119 uint16 MultipleInterruptSelect; // 0x5c
120 uint8 PCIRevisionID; // 0x5e should be 0x10
121 uint8 rsvd3; // 0x5f
122 uint16 TSAD; // 0x60 Transmit Status of All Descriptors
123 uint16 BMCR; // 0x62 Basic Mode Control
124 uint16 BMSR; // 0x64 Basic Mode Status
125 uint16 ANAR; // 0x66 Auto-Negotiation Advertisement
126 uint16 ANLPAR; // 0x68 "" Link Partner
127 uint16 ANER; // 0x6a "" Expansion
128 uint16 DisconnectCounter; // 0x6c
129 uint16 FalseCarrierSenseCounter; // 0x6e
130 uint16 NWayTest; // 0x70
131 uint16 RX_ER_Counter; //0x72
132 uint16 CSConfiguration; // 0x74
133 uint16 rsvd4;
134 uint32 PHY1; //0x78
135 uint32 Twister; // 0x7c
136 uint8 PHY2; // 0x80
137 } PACKED;
138
139 struct Packet {
140 uint32 pid;
141 uint16 size;
142 byte packet[MAX_PACKET_SIZE];
143 };
144
145 // IEEE 802.3 MAC, Ethernet-II
146 struct EthFrameII {
147 byte destMAC[6];
148 byte srcMAC[6];
149 byte type[2];
150 } PACKED;
151
152 enum EEPROMField {
153 EEPROM_NodeAddress0 = 0x00,
154 EEPROM_NodeAddress1 = 0x01,
155 EEPROM_NodeAddress2 = 0x02,
156 EEPROM_DeviceID = 0x03,
157 EEPROM_ManifacturerID = 0x07,
158 EEPROM_PCIParam = 0x08,
159 EEPROM_RomInfo = 0x09,
160 EEPROM_OEMNodeAddress0 = 0x0a,
161 EEPROM_OEMNodeAddress1 = 0x0b,
162 EEPROM_OEMNodeAddress2 = 0x0c,
163 EEPROM_SoftwareInfo = 0x0d,
164 EEPROM_CompWord = 0x0e,
165 EEPROM_SoftwareInfo2 = 0x0f,
166 EEPROM_Caps = 0x10,
167 EEPROM_InternalConfig0 = 0x12,
168 EEPROM_InternalConfig1 = 0x13,
169 EEPROM_SubsystemVendorID = 0x17,
170 EEPROM_SubsystemID = 0x18,
171 EEPROM_MediaOptions = 0x19,
172 EEPROM_SmbAddress = 0x1b,
173 EEPROM_PCIParam2 = 0x1c,
174 EEPROM_PCIParam3 = 0x1d,
175 EEPROM_Checksum = 0x20
176 };
177
178 /*
179 *
180 */
181 class rtl8139_NIC: public PCI_Device {
182 protected:
183 uint16 mEEPROM[0x40];
184 bool mEEPROMWritable;
185 Registers mRegisters;
186 uint16 mIntStatus;
187 int mRingBufferSize;
188 bool mGoodBSA;
189 EthTunDevice * mEthTun;
190 sys_mutex mLock;
191 int mVerbose;
192 byte mHead;
193 byte mTail;
194 byte mActive;
195 byte mWatermark;
196 byte mLast;
197 byte mLastPackets[2];
198 uint32 mPid;
199 Packet mPackets[MAX_PACKETS];
200 byte mMAC[6];
201
202 void PCIReset()
203 {
204 IO_RTL8139_TRACE("PCIReset()\n"); // PCI config
205 memset(mConfig, 0, sizeof mConfig);
206 // 0-3 set by totalReset()
207 // mConfig[0x04] = 0x07; // io+memory+master
208
209 mConfig[0x08] = 0x00; // revision
210 mConfig[0x09] = 0x00; //
211 mConfig[0x0a] = 0x00; // ClassCode 0x20000: Ethernet network controller
212 mConfig[0x0b] = 0x02; //
213
214 mConfig[0x0e] = 0x00; // header-type (single-function PCI device)
215
216 mConfig[0x3c] = IO_PIC_IRQ_ETHERNET1; // interrupt line
217 mConfig[0x3d] = 1; // interrupt pin (default is 1)
218 mConfig[0x3e] = 5; // MinGnt (default is 5 = 0x05 = 0101b)
219 mConfig[0x3f] = 48; // MaxLat (default is 48 = 0x30 = 110000b)
220
221 mConfig[0x34] = 0xdc;
222
223 mIORegSize[0] = 0x100;
224 mIORegType[0] = PCI_ADDRESS_SPACE_IO;
225 assignIOPort(0, 0x1800);
226 }
227
228 void totalReset()
229 {
230 IO_RTL8139_TRACE("totalReset()\n"); // PCI config
231 /* FIXME: resetting can be done more fine-grained (see TotalReset cmd).
232 * this is reset ALL regs.
233 */
234
235 mIORegSize[0] = 256; // 128;
236 mIORegType[0] = PCI_ADDRESS_SPACE_IO;
237 // internals
238 mEEPROMWritable = false;
239 memset(&mRegisters, 0, sizeof mRegisters);
240 mIntStatus = 0;
241 mRingBufferSize = 8192;
242 mHead = 0;
243 mTail = 0;
244 mActive = 0;
245 mWatermark = 0;
246 mLastPackets[0] = 0;
247 mLastPackets[1] = 0;
248 mGoodBSA = false;
249 // EEPROM config (FIXME: endianess)
250
251 // set up mac address
252 byte *ptr = (byte*)&mRegisters;
253 memcpy(ptr, mMAC, 6);
254 // negotiate link, actually set it to valid 100 half duplex
255 mRegisters.BMSR = 0x2025; // 0x4025;
256 mRegisters.BMCR = 0x2000; // 0x3010; // 100mbs, no ane
257 mRegisters.Config1 = 0x00;
258 mRegisters.CommandRegister = 0x01;
259 mRegisters.TxConfiguration = 0x63000000; // rtl8139
260 mRegisters.MediaStatus = 0x90;
261 mRegisters.CBA = 0;
262 mRegisters.CAPR = 0xfff0;
263
264 memset(mEEPROM, 0, sizeof mEEPROM);
265 mEEPROM[EEPROM_DeviceID] = 0x8139; //0x9200;
266 mEEPROM[EEPROM_ManifacturerID] = 0x10ec; //0x6d50;
267 mEEPROM[EEPROM_PCIParam] = 0; //0x2940;
268 mEEPROM[EEPROM_RomInfo] = 0; // no ROM
269 mEEPROM[EEPROM_OEMNodeAddress0] = mEEPROM[EEPROM_NodeAddress0];
270 mEEPROM[EEPROM_OEMNodeAddress1] = mEEPROM[EEPROM_NodeAddress1];
271 mEEPROM[EEPROM_OEMNodeAddress2] = mEEPROM[EEPROM_NodeAddress2];
272 mEEPROM[EEPROM_SoftwareInfo] = 0; //0x4010;
273 mEEPROM[EEPROM_CompWord] = 0;
274 mEEPROM[EEPROM_SoftwareInfo2] = 0; //0x00aa;
275 mEEPROM[EEPROM_Caps] = 0x72a2;
276 mEEPROM[EEPROM_InternalConfig0] = 0;
277 mEEPROM[EEPROM_InternalConfig1] = 0; //0x0040; // default is 0x0180
278 mEEPROM[EEPROM_SubsystemVendorID] = 0x10ec; //0x10b7;
279 mEEPROM[EEPROM_SubsystemID] = 0x8139; //0x9200;
280 mEEPROM[EEPROM_MediaOptions] = 0x000a;
281 mEEPROM[EEPROM_SmbAddress] = 0; //0x6300;
282 mEEPROM[EEPROM_PCIParam2] = 0; //0xffb7;
283 mEEPROM[EEPROM_PCIParam3] = 0; //0xb7b7;
284 mEEPROM[EEPROM_Checksum] = 0;
285
286 // PCI config follow-ups
287 mConfig[0x00] = mEEPROM[EEPROM_SubsystemVendorID] & 0xff; // vendor ID
288 mConfig[0x01] = mEEPROM[EEPROM_SubsystemVendorID] >> 8;
289 mConfig[0x02] = mEEPROM[EEPROM_DeviceID] & 0xff; // unit ID
290 mConfig[0x03] = mEEPROM[EEPROM_DeviceID] >> 8;
291 }
292
293 void setCR(uint8 cr)
294 {
295 if (cr & 0x10) {
296 // FIXME: care about params
297 totalReset();
298 }
299 if (cr & 0x08) {
300 mRegisters.CommandRegister |= 0x08;
301 // enable receiver
302 }
303 if (cr & 0x04) {
304 mRegisters.CommandRegister |= 0x04;
305 // enable transmitter
306 }
307 if (cr & ~(0x1c)) {
308 IO_RTL8139_WARN("command register write invalid byte: %0x\n", cr);
309 }
310 }
311
312 void maybeRaiseIntr()
313 {
314 IO_RTL8139_TRACE("maybeRaiseIntr()\n");
315 if (mRegisters.InterruptMask & mIntStatus) {
316 //mIntStatus |= IS_interruptLatch;
317 IO_RTL8139_TRACE("Generating interrupt. mIntStatus=%04x\n", mIntStatus);
318 pic_raise_interrupt(mConfig[0x3c]);
319 }
320 }
321
322 void TxPacket(uint32 address, uint32 size)
323 {
324 byte pbuf[MAX_PACKET_SIZE];
325 byte * p;
326 uint32 crc;
327 uint32 psize;
328
329 p = pbuf;
330 IO_RTL8139_TRACE("address: %08x, size: %04x\n", address, size);
331 if (ppc_dma_read(pbuf, address, size)) {
332 /* if (mVerbose > 1) {
333 debugDumpMem(ppc_addr, size);
334 }*/
335 crc = ether_crc(size, p);
336 psize = size;
337 pbuf[psize+0] = crc;
338 pbuf[psize+1] = crc>>8;
339 pbuf[psize+2] = crc>>16;
340 pbuf[psize+3] = crc>>24;
341 psize += 4;
342
343 uint w = mEthTun->sendPacket(pbuf, psize);
344 if (w) {
345 if (w == psize) {
346 IO_RTL8139_TRACE("EthTun: %d bytes sent.\n", psize);
347 } else {
348 IO_RTL8139_WARN("EthTun: ARGH! send error: only %d of %d bytes sent\n", w, psize);
349 }
350 } else {
351 IO_RTL8139_WARN("EthTun: ARGH! send error in packet driver.\n");
352 }
353 maybeRaiseIntr();
354 }
355 }
356
357 public:
358 rtl8139_NIC(EthTunDevice *aEthTun, const byte *mac)
359 : PCI_Device("rtl8139 Network interface card", 0x1, 0xd)
360 {
361 int e;
362 if ((e = sys_create_mutex(&mLock))) throw IOException(e);
363 mEthTun = aEthTun;
364 memcpy(mMAC, mac, 6);
365 mPid = 0;
366 PCIReset();
367 totalReset();
368 }
369
370 void transferPacket(bool raiseIntr)
371 {
372 uint32 addr;
373 uint32 base = mRegisters.RxBufferStartAddr;
374 bool good;
375
376 if (mTail == mHead) {
377 return;
378 }
379 addr = base + mRegisters.CBA;
380 if (mRegisters.CBA > mRingBufferSize) {// sending outside, could cause problems?
381 good = false;
382 } else {
383 good = true;
384 }
385 #if 0
386 if ((mRegisters.CBA) > mRingBufferSize) {
387 IO_RTL8139_TRACE("client ring buffer wrap around [%d]\n", raiseIntr);
388 addr = base;
389 mRegisters.CBA = 0;
390 mRegisters.CAPR = 0xfff0;
391 // mRegisters.CommandRegister |= 1;
392 return;
393 }
394 #endif
395 ppc_dma_write(addr, mPackets[mTail].packet, mPackets[mTail].size);
396 IO_RTL8139_TRACE("wrote %04x bytes to the ring buffer\n", mPackets[mTail].size);
397 mRegisters.EarlyRxByteCount = mPackets[mTail].size;
398 mRegisters.EarlyRxStatus = 8;
399 mRegisters.CBA += mPackets[mTail].size;
400 mRegisters.CommandRegister &= 0xfe; // RxBuffer has data
401 mLastPackets[1] = mLastPackets[0];
402 mLastPackets[0] = mTail;
403 mActive--;
404 IO_RTL8139_TRACE("Outgoing - Addr: %08x, Pid: %08x, Size: %04x\n", addr, mPackets[mTail].pid, mPackets[mTail].size-4);
405 if (good) {
406 mTail = (mTail+1) % MAX_PACKETS;
407 }
408 if (raiseIntr) {
409 mIntStatus |= 1;
410 maybeRaiseIntr();
411 }
412 }
413
414 virtual ~rtl8139_NIC()
415 {
416 mEthTun->shutdownDevice();
417 delete mEthTun;
418 sys_destroy_mutex(mLock);
419 }
420
421 void readConfig(uint reg)
422 {
423 //if (mVerbose) IO_RTL8139_TRACE("readConfig %02x\n", reg);
424 if (reg >= 0xdc) {
425 IO_RTL8139_WARN("readConfig(%x)\n", reg);
426 }
427 sys_lock_mutex(mLock);
428 PCI_Device::readConfig(reg);
429 sys_unlock_mutex(mLock);
430 }
431
432 void writeConfig(uint reg, int offset, int size)
433 {
434 //if (mVerbose) IO_RTL8139_TRACE("writeConfig %02x, %d, %d\n", reg, offset, size);
435 sys_lock_mutex(mLock);
436 if (reg >= 0xdc) {
437 IO_RTL8139_WARN("writeConfig(%x, %d, %d)\n", reg, offset, size);
438 }
439 PCI_Device::writeConfig(reg, offset, size);
440 sys_unlock_mutex(mLock);
441 }
442
443 bool readDeviceIO(uint r, uint32 port, uint32 &data, uint size)
444 {
445 if (r != 0) return false;
446 bool retval = false;
447 // IO_RTL8139_TRACE("readDevice waiting for mLock\n");
448 sys_lock_mutex(mLock);
449 // IO_RTL8139_TRACE("readDevice has mLock\n");
450
451 if (port == 0x3e) {
452 // IntStatus (no matter which window)
453 if (size != 2) {
454 IO_RTL8139_WARN("unaligned read from IntStatus\n");
455 }
456 IO_RTL8139_TRACE("read IntStatus = %04x\n", mIntStatus);
457 data = mIntStatus;
458 mIntStatus = 0; // a read resets the interrupt status register
459 retval = true;
460 } else if ((port >= 0) && (port+size <= sizeof(Registers))) {
461 // read from (standard) register
462 data = 0;
463 memcpy(&data, ((byte*)&mRegisters)+port, size);
464
465 switch (port) {
466 case 0x48:
467 IO_RTL8139_TRACE("read Timer = %08x\n", data);
468 break;
469 case 0x37: {
470 IO_RTL8139_TRACE("read Command Register = %02x\n", data);
471 break;
472 }
473 case 0x64: {
474 IO_RTL8139_TRACE("read Basic Mode Status = %04x\n", data);
475 if ((mTail != mHead) && (mRegisters.CommandRegister & 0x01)) {
476 transferPacket(true);
477 }
478 break;
479 }
480 default:
481 IO_RTL8139_TRACE("read reg %04x (size %d) = %08x\n", port, size, data);
482 break;
483 }
484 retval = true;
485 }
486 sys_unlock_mutex(mLock);
487 // IO_RTL8139_TRACE("readDevice freed mLock\n");
488 return retval;
489 }
490
491 bool writeDeviceIO(uint r, uint32 port, uint32 data, uint size)
492 {
493 uint32 original;
494
495 if (r != 0) return false;
496 bool retval = false;
497 // IO_RTL8139_TRACE("writeDevice waiting for mLock\n");
498 sys_lock_mutex(mLock);
499 // IO_RTL8139_TRACE("writeDevice has mLock\n");
500 original = data;
501 if (port == 0x37) {
502 // CommandReg (no matter which window)
503 if (size != 1) {
504 IO_RTL8139_WARN("unaligned write to CommandReg\n");
505 }
506 setCR(data);
507 retval = true;
508 } else if ((port >= 0) && (port+size <= sizeof(Registers))) {
509 switch (port) {
510 case 0x3c: {
511 IO_RTL8139_TRACE("write Interrupt Mask Register %04x (now = %04x)\n", data, mRegisters.InterruptMask);
512 mRegisters.InterruptMask = data;
513 break;
514 }
515 case 0x10: {
516 IO_RTL8139_TRACE("write to TS0, got data to send %08x\n", data);
517 TxPacket(mRegisters.TxStartAddrD0, data & 0x0fff);
518 mRegisters.TxStatusD0 |= ((1 << 13)|(1<<15)); // set ownership
519 mIntStatus |= 4; // Tx Ok
520 break;
521 }
522 case 0x14: {
523 IO_RTL8139_TRACE("write to TS1, got data to send %08x\n", data);
524 TxPacket(mRegisters.TxStartAddrD1, data & 0x0fff);
525 mRegisters.TxStatusD1 |= ((1 << 13)|(1<<15)); // set ownership
526 mIntStatus |= 4; // Tx Ok
527 break;
528 }
529 case 0x18: {
530 IO_RTL8139_TRACE("write to TS2, got data to send %08x\n", data);
531 TxPacket(mRegisters.TxStartAddrD2, data & 0x0fff);
532 mRegisters.TxStatusD2 |= ((1 << 13)|(1<<15)); // set ownership
533 mIntStatus |= 4; // Tx Ok
534 break;
535 }
536 case 0x1c: {
537 IO_RTL8139_TRACE("write to TS3, got data to send %08x\n", data);
538 TxPacket(mRegisters.TxStartAddrD3, data & 0x0fff);
539 mRegisters.TxStatusD3 |= ((1 << 13)|(1<<15)); // set ownership
540 mIntStatus |= 4; // Tx Ok
541 break;
542 }
543 case 0x20: {
544 IO_RTL8139_TRACE("write to TxSA0, address %08x\n", data);
545 mRegisters.TxStartAddrD0 = data;
546 break;
547 }
548 case 0x24: {
549 IO_RTL8139_TRACE("write to TxSA1, address %08x\n", data);
550 mRegisters.TxStartAddrD1 = data;
551 break;
552 }
553 case 0x28: {
554 IO_RTL8139_TRACE("write to TxSA2, address %08x\n", data);
555 mRegisters.TxStartAddrD2 = data;
556 break;
557 }
558 case 0x2c: {
559 IO_RTL8139_TRACE("write to TxSA3, address %08x\n", data);
560 mRegisters.TxStartAddrD3 = data;
561 break;
562 }
563 case 0x30: {
564 IO_RTL8139_TRACE("write to RxBSA, address %08x\n", data);
565 mRegisters.RxBufferStartAddr = data;
566 mRegisters.CBA = 0;
567 mRegisters.CAPR = 0xfff0;
568 mRegisters.CommandRegister |= 1;
569 mGoodBSA = true;
570 transferPacket(true);
571 break;
572 }
573 case 0x38: {
574 IO_RTL8139_TRACE("update to CAPR: CAPR %04x, CBA %04x\n", data, mRegisters.CBA);
575 mRegisters.CAPR = data;
576 if (mRegisters.CAPR >= mRegisters.CBA) {
577 IO_RTL8139_WARN("Bad packet read by client? Active %02x, CAPR %04x, CBA %04x, Tail %02x, Head %02x\n", mActive, mRegisters.CAPR, mRegisters.CBA, mTail, mHead);
578 mRegisters.CBA = mRegisters.CAPR + 0x10;
579 }
580 if (mRegisters.CAPR > mRingBufferSize) { //client knows about wrap, so wrap
581 mRegisters.CBA = 0;
582 mIntStatus |= 1; // fake send
583 maybeRaiseIntr();
584 IO_RTL8139_TRACE("client wrap on CAPR set Active %02x, CAPR %04x, CBA %04x, Tail %02x, Head %02x\n", mActive, mRegisters.CAPR, mRegisters.CBA, mTail, mHead);
585 /*
586 mIntStatus |= 1; // fake send
587 maybeRaiseIntr();
588 mRegisters.CAPR = 0xfff0;
589 mRegisters.CommandRegister |= 1;
590 */
591 } else {
592 if (mTail != mHead) {
593 transferPacket(false);
594 } else {
595 mRegisters.CommandRegister |= 1;
596 }
597 }
598 break;
599 }
600 case 0x44: {
601 IO_RTL8139_TRACE("write to RxConfiguration, data %08x\n", data);
602 switch ((data & 0x1800)) {
603 case 0x0000: mRingBufferSize = 8192; break;
604 case 0x0800: mRingBufferSize = 16384; break;
605 case 0x1000: mRingBufferSize = 32768; break;
606 case 0x1800: mRingBufferSize = 65536; break;
607 default: mRingBufferSize = 8192;
608 };
609 IO_RTL8139_TRACE("RingBuffer Size: %08x\n", mRingBufferSize);
610 break;
611 }
612 case 0x62: {
613 IO_RTL8139_TRACE("write Basic Mode Control %04x\n", data);
614 //mIntStatus |= 0x2000; // cable length changed, receive enabled
615 mRegisters.BMCR = data & 0xfdff;
616 break;
617 }
618 default:
619 IO_RTL8139_TRACE("write to register port=%04x, size=%d, data=0x%08x\n", port, size, data);
620 // write to (standard) register
621 memcpy(((byte*)&mRegisters)+port, &data, size);
622 }
623 retval = true;
624 }
625 sys_unlock_mutex(mLock);
626 return retval;
627 }
628
629 void handleRxQueue()
630 {
631 uint16 header;
632 uint16 psize;
633 byte rxPacket[MAX_PACKET_SIZE];
634 uint16 rxPacketSize;
635 byte tmp;
636 static byte broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
637
638 while (1) {
639 while (mEthTun->waitRecvPacket() != 0) {
640 // don't block the system in case of (repeated) error(s)
641 sys_suspend();
642 }
643 rxPacketSize = mEthTun->recvPacket(rxPacket, sizeof rxPacket);
644 if (!rxPacketSize) {
645 // don't block the system in case of (repeated) error(s)
646 sys_suspend();
647 continue;
648 }
649 IO_RTL8139_TRACE("got packet from the world at large\n");
650 if (!mGoodBSA) continue;
651 /* if (mVerbose > 1) {
652 debugDumpMem(rxPacket, rxPacketSize);
653 }*/
654 header = 0;
655 if (rxPacketSize < 64) {
656 for ( ; rxPacketSize < 60; rxPacketSize++) {
657 rxPacket[rxPacketSize] = 0;
658 }
659 //header |= Rx_RUNT; // set runt status
660 }
661 /* pad to a 4 byte boundary */
662 for (int i = 4-(rxPacketSize % 4); i != 0; i--) {
663 rxPacket[rxPacketSize++] = 0;
664 }
665 if (memcmp(rxPacket, broadcast, 6) == 0) {
666 header |= Rx_BAR;
667 }
668 // IO_RTL8139_TRACE("handleRxQueue waiting for mLock\n");
669 sys_lock_mutex(mLock);
670 // IO_RTL8139_TRACE("handleRxQueue has mLock\n");
671 if (memcmp(rxPacket, (byte*)&(mRegisters.id0), 6) == 0) {
672 /*if (mVerbose > 1) IO_RTL8139_TRACE("Physical Address Match\n");*/
673 header |= Rx_PAM;
674 }
675 // check crc?
676 header |= Rx_ROK;
677 psize = rxPacketSize;
678 IO_RTL8139_TRACE("Incoming - Pid: %08x, Header: %04x, Size: %04x\n", mPid, header, psize);
679 mPackets[mHead].packet[0] = header;
680 mPackets[mHead].packet[1] = header>>8;
681 mPackets[mHead].packet[2] = psize;
682 mPackets[mHead].packet[3] = psize>>8;
683 memcpy(&(mPackets[mHead].packet[4]), rxPacket, rxPacketSize);
684 mPackets[mHead].size = rxPacketSize+4;
685 mPackets[mHead].pid = mPid;
686 tmp = mHead;
687 if (mHead == mTail) { /* first recent packet buffer */
688 mHead = (mHead+1) % MAX_PACKETS;
689 } else {
690 mHead = (mHead+1) % MAX_PACKETS;
691 if (mHead == mTail) {
692 mHead = tmp; // reset it back
693 IO_RTL8139_WARN("Internal Buffer wrapped around\n");
694 }
695 }
696 if (tmp != mHead) {
697 mPid++;
698 mActive++;
699 if (mActive > mWatermark) {
700 IO_RTL8139_TRACE("Watermark: %02x\n", mWatermark);
701 mWatermark = mActive;
702 }
703 }
704 if (mRegisters.CommandRegister & 1) { /* no packets in process, kick one out */
705 transferPacket(true);
706 }
707 sys_unlock_mutex(mLock);
708 // IO_RTL8139_TRACE("handleRxQueue freed mLock\n");
709 }
710 }
711
712 }; // end of rtl8139 class
713
714 static void *rtl8139HandleRxQueue(void *nic)
715 {
716 rtl8139_NIC *NIC = (rtl8139_NIC *)nic;
717 NIC->handleRxQueue();
718 return NULL;
719 }
720
721 bool rtl8139_installed = false;
722
723 #include "configparser.h"
724 #include "tools/strtools.h"
725
726 #define RTL8139_KEY_INSTALLED "pci_rtl8139_installed"
727 #define RTL8139_KEY_MAC "pci_rtl8139_mac"
728
729 void rtl8139_init()
730 {
731 if (gConfig->getConfigInt(RTL8139_KEY_INSTALLED)) {
732 rtl8139_installed = true;
733 byte mac[6];
734 mac[0] = 0xde;
735 mac[1] = 0xad;
736 mac[2] = 0xca;
737 mac[3] = 0xfe;
738 mac[4] = 0x12;
739 mac[5] = 0x34;
740 if (gConfig->haveKey(RTL8139_KEY_MAC)) {
741 String macstr_;
742 gConfig->getConfigString(RTL8139_KEY_MAC, macstr_);
743 // do something useful with mac
744 const char *macstr = macstr_.contentChar();
745 byte cfgmac[6];
746 for (uint i=0; i<6; i++) {
747 uint64 v;
748 if (!parseIntStr(macstr, v, 16) || (v>255) || ((*macstr != ':') && (i!=5))) {
749 IO_RTL8139_ERR("error in config key %s:"
750 "expected format: XX:XX:XX:XX:XX:XX, "
751 "where X stands for any digit or the "
752 "letters a-f, A-F (error at: %s)\n",
753 RTL8139_KEY_MAC, macstr);
754 }
755 macstr++;
756 cfgmac[i] = v;
757 }
758 memcpy(mac, cfgmac, sizeof mac);
759 }
760 EthTunDevice *ethTun = createEthernetTunnel();
761 if (!ethTun) {
762 IO_3C90X_ERR("Couldn't create ethernet tunnel\n");
763 exit(1);
764 }
765 if (ethTun->initDevice()) {
766 IO_3C90X_ERR("Couldn't initialize ethernet tunnel\n");
767 exit(1);
768 }
769 #if 0
770 printf("Creating RealTek rtl8139 NIC emulation with eth_addr = ");
771 for (uint i=0; i<6; i++) {
772 if (i<5) {
773 printf("%02x:", mac[i]);
774 } else {
775 printf("%02x", mac[i]);
776 }
777 }
778 printf("\n");
779 #endif
780 rtl8139_NIC *MyNIC = new rtl8139_NIC(ethTun, mac);
781 gPCI_Devices->insert(MyNIC);
782 sys_thread rxthread;
783 sys_create_thread(&rxthread, 0, rtl8139HandleRxQueue, MyNIC);
784 }
785 }
786
787 void rtl8139_done()
788 {
789 }
790
791 void rtl8139_init_config()
792 {
793 gConfig->acceptConfigEntryIntDef(RTL8139_KEY_INSTALLED, 0);
794 gConfig->acceptConfigEntryString(RTL8139_KEY_MAC, false);
795 }

  ViewVC Help
Powered by ViewVC 1.1.26