/[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

Annotation of /src/io/rtl8139/rtl8139.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 8 months ago) by dpavlin
File size: 22082 byte(s)
import upstream CVS
1 dpavlin 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