12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241 |
- MODULE RTL8169; (** AUTHOR "Roger Keller"; PURPOSE "Driver for RealTek RTL8169 Ethernet Controllers"; *)
- (*
- Reference: RealTek, "RealTek Gigabit Ethernet Media Access Controller
- with Power Management RTL8169S/RTL8110S Registers"
- Revision 1.0, March 2003
- *)
- IMPORT
- SYSTEM, Kernel, Machine, PCI,
- Objects, Modules, Plugins, Network, KernelLog;
- CONST
- Name = "RTL8169#";
- Description = "RealTek 8169 Gigabit ethernet driver";
- MaxETHFrameSize = 1514;
- TxMaxSize = 1600; (* Max size of tx buffers *)
- RxMaxSize = 600H; (* Max size for received frames = 1536 bytes *)
- RxRingSize = 1024; (* Rx Ring of 116 buffers *)
- TxRingSize = 1024; (* Tx Ring of 116 buffers *)
- SizeOfRxTxFDHdr = 16; (* size of Rx / Tx Descriptor Header *)
- InterruptMask = {0, 1, 2, 3, 4, 5, 6, 7, 15}; (* interrupts to handle *)
- Promisc = FALSE; (* enable Promiscuous mode *)
- UnknownHW = 0;
- RTL8169 = 1;
- RTL8169S = 2;
- DebugFind = 0;
- DebugInit = 1;
- DebugConfigs = 2;
- DebugHWVer = 3;
- DebugMAC = 4;
- DebugStatus = 5;
- DebugRxRing = 6;
- DebugTxRing = 7;
- DebugReceive = 8;
- DebugTransmit = 9;
- DebugInterrupt = 10;
- DebugCleanup = 31;
- Debug = {DebugFind, DebugInit, DebugTxRing, DebugCleanup};
- VAR
- installed: LONGINT; (* number of installed devices *)
- TYPE
- (* base Rx/Tx descriptor, as described in RTL8169 specs *)
- RxTxDescriptor = RECORD
- flags: SET;
- vLanTag: LONGINT;
- bufAdrLo, bufAdrHi: LONGINT;
- END;
- (* buffer for transmission *)
- TxBuffer = POINTER TO RECORD
- data: ARRAY TxMaxSize OF CHAR;
- next: TxBuffer;
- END;
- (* wrapper for Network.Buffer to be able to form rings *)
- RxBuffer = POINTER TO RECORD
- buf: Network.Buffer;
- next: RxBuffer;
- END;
- (* LinkDevice: interface to Bluebottle *)
- LinkDevice = OBJECT (Network.LinkDevice)
- VAR
- ctrl: Controller;
- hw: LONGINT;
- PROCEDURE Linked*(): LONGINT;
- BEGIN
- RETURN ctrl.linkStatus;
- END Linked;
- PROCEDURE DoSend*(dst: Network.LinkAdr; type: LONGINT; CONST l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
- BEGIN
- ctrl.SendFrame(dst, type, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen);
- END DoSend;
- PROCEDURE Finalize(connected: BOOLEAN);
- BEGIN
- ctrl.Finalize;
- Finalize^(connected);
- END Finalize;
- END LinkDevice;
- (* Controller: interface to the RTL8169 hardware *)
- Controller = OBJECT
- VAR
- next: Controller; (* next controller in list *)
- base: ADDRESS; irq: LONGINT;
- dev: LinkDevice;
- rds: ARRAY RxRingSize OF RxTxDescriptor;
- tds: ARRAY TxRingSize OF RxTxDescriptor;
- curRD, curTD: LONGINT;
- firstRD, firstTD: LONGINT;
- lastRD, lastTD: LONGINT;
- (*rxBuffer, rxLast: TxBuffer;*)
- rxBuffer, rxLast: RxBuffer;
- txBuffer, txLast: TxBuffer;
- nofFreeTx: LONGINT; (* number of free tx descriptors *)
- nRxOverflow: HUGEINT;
- nTxOverflow: HUGEINT;
- nRxFrames, nTxFrames: LONGINT;
- nRxErrorFrames: LONGINT;
- nTxErrorFrames: LONGINT;
- linkStatus: LONGINT;
- PROCEDURE &Init*(dev: LinkDevice; base: ADDRESS; irq: LONGINT);
- VAR
- res: WORD; i: LONGINT;
- s: SET;
- BEGIN
- (* update list of installed controllers, insert at head *)
- SELF.next := installedControllers;
- installedControllers := SELF;
- SELF.base := base;
- SELF.dev := dev;
- SELF.irq := irq;
- dev.ctrl := SELF;
- nRxOverflow := 0;
- nTxOverflow := 0;
- nRxFrames := 0;
- nTxFrames := 0;
- nRxErrorFrames := 0;
- nTxErrorFrames := 0;
- (* tell the system that the nic calculates the checksums for tcp, udp and ip packets *)
- dev.calcChecksum := {Network.ChecksumIP, Network.ChecksumTCP, Network.ChecksumUDP};
- (* set ethernet broadcast address: FF-FF-FF-FF-FF-FF *)
- FOR i := 0 TO 5 DO
- dev.broadcast[i] := 0FFX
- END;
- (* make sure PIO and MMIO are enabled*)
- s := SYSTEM.VAL(SET, Read8(52H));
- IF ~ (2 IN s) THEN
- KernelLog.String("I/O Mapping is disabled!");
- HALT(1000);
- END;
- IF ~ (3 IN s) THEN
- KernelLog.String("MMIO is disabled!");
- HALT(1000);
- END;
- (* find out if we're on 1GBps *)
- s := SYSTEM.VAL(SET, Read8(6CH));
- (* if not, try to enable 1GBps ... *)
- IF ~ (4 IN s) THEN
- (* reset the hardware and enable 1000baseTx *)
- HwReset;
- EnableTBI;
- END;
- (* read and store MAC address *)
- ReadMACAddress;
- (* find out hardware version *)
- GetHardwareVersion;
- (* soft reset the chip *)
- ResetNIC;
- (* enable Tx and Rx *)
- EnableTxRx(TRUE, TRUE);
- (* set Max Transmit Packet Size (MTPS):
- register counts in 32 byte units -> 32H * 32 bytes = 1600 bytes *)
- Write8(0ECH, 32H);
- (* set Receive Packet Maximum Size (RMS) *)
- Write16(0DAH, RxMaxSize);
- (* set Tx config register:
- let the nic compute CRCs of frames in Tx *)
- s := SYSTEM.VAL(SET, Read32(40H));
- s := (s - {17..18, 19}) + {8..10, 25};
- Write32(40H, SYSTEM.VAL(LONGINT, s));
- (* config c+ command register:
- PCI multiple read/write enable;
- Receive Checksum Offload enable *)
- s := SYSTEM.VAL(SET, Read16(0E0H));
- s := s + {3, 5};
- Write16(0E0H, SYSTEM.VAL(LONGINT, s));
- (* setup Tx (normal priority) ring *)
- res := SetupTxRing();
- (* set Transmit Normal Priority Descriptor Start Address (TNPDS) *)
- Write32(20H, res);
- Write32(20H + 4, 0);
- (* setup Rx ring *)
- res := SetupRxRing();
- (* set Receive Descriptor Start Address (RDSAR) *)
- Write32(0E4H, res);
- Write32(0E4H + 4, 0);
- (* reset Rx missed packet counter *)
- Write32(04CH, 0);
- (* configure receiver *)
- ConfigRx;
- (* install interrupt handler *)
- IF (irq >= 1) & (irq <= 15) THEN
- Objects.InstallHandler(SELF.HandleInterrupt, Machine.IRQ0 + irq)
- END;
- (* enable interrupts *)
- Write16(3CH, SYSTEM.VAL(LONGINT, InterruptMask));
- UpdateLinkStatus;
- (* register device with Network *)
- Network.registry.Add(dev, res);
- ASSERT(res = Plugins.Ok);
- INC(installed);
- IF DebugConfigs IN Debug THEN
- DebugConfig;
- END;
- END Init;
- PROCEDURE SendFrame(dst: Network.LinkAdr; type: LONGINT; CONST l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
- VAR
- txLen, offset, type4: LONGINT;
- bufBase: ADDRESS;
- chksums: SET;
- BEGIN {EXCLUSIVE}
- IF nofFreeTx <= 0 THEN
- KernelLog.String("no tx buffers"); KernelLog.Ln;
- INC(nTxOverflow);
- END;
- AWAIT(nofFreeTx > 0);
- txLen := 14 + h3len + h4len + dlen;
- bufBase := ADDRESSOF(txBuffer.data);
- (* generate ethernet frame: setup eth header, move data *)
- (* set destination mac address (first 6 bytes of eth frame) *)
- SYSTEM.MOVE(ADDRESSOF(dst[0]), bufBase, 6);
- (* set source mac address (6 bytes @ offset 6 of eth frame) *)
- SYSTEM.MOVE(ADDRESSOF(dev.local[0]), bufBase + 6, 6);
- (* set upper layer type, bring type from host to network byte order *)
- SYSTEM.PUT16(bufBase + 12, ROT(SYSTEM.VAL(INTEGER, SHORT(type)), 8));
- offset := 14; (* eth header has 14 bytes *)
- (* move layer 3 and layer 4 headers, data *)
- IF h3len > 0 THEN
- SYSTEM.MOVE(ADDRESSOF(l3hdr[0]), bufBase + offset, h3len);
- INC(offset, h3len);
- END;
- IF h4len > 0 THEN
- SYSTEM.MOVE(ADDRESSOF(l4hdr[0]), bufBase + offset, h4len);
- INC(offset, h4len);
- END;
- IF offset + dlen < MaxETHFrameSize THEN
- SYSTEM.MOVE(ADDRESSOF(data[0]) + dofs, bufBase + offset, dlen);
- INC(offset, dlen);
- END;
- (* make the frame at least 64 bytes long *)
- WHILE offset < 60 DO
- txBuffer.data[offset] := CHR(0);
- INC(offset);
- INC(txLen);
- END;
- IF DebugTransmit IN Debug THEN
- KernelLog.String("Sending frame of length ");
- KernelLog.Int(txLen, 0);
- KernelLog.Ln;
- (*KernelLog.Memory(bufBase, txLen);*)
- END;
- (* find out which protocols are used;
- let the NIC calc the checksums for IP, TCP and UCP headers *)
- chksums := {};
- IF type = 0800H THEN
- INCL(chksums, 18); (* offload IP checksum *)
- type4 := SYSTEM.VAL(SHORTINT, l3hdr[9]); (* get type if IP data *)
- IF type4 = 6 THEN (* TCP/IP *)
- INCL(chksums, 16); (* offload TCP checksum *)
- ELSIF type4 = 17 THEN
- INCL(chksums, 17); (* offload UDP checksum *)
- END;
- END;
- (* update Tx Descriptor:
- set OWN=1, FS=1, LS=1, checksum offloads;
- set size of packet to be transmitted *)
- tds[curTD].flags := tds[curTD].flags * {30}; (* only keep EOR bit *)
- tds[curTD].flags := tds[curTD].flags + {31, 29, 28} + chksums;
- tds[curTD].flags := tds[curTD].flags + (SYSTEM.VAL(SET, txLen) * {0..15});
- (* move to next Tx Descriptor, Tx Buffer *)
- INC(curTD);
- IF curTD = TxRingSize THEN
- curTD := firstTD;
- END;
- txBuffer := txBuffer.next;
- DEC(nofFreeTx);
- (* tell the nic that there's some eth frame waiting to be transmitted (set NPQ=1) *)
- Write8(38H, SYSTEM.VAL(LONGINT, {6}));
- END SendFrame;
- PROCEDURE ConfigRx;
- VAR s: SET;
- BEGIN
- (* set Rx config register:
- let the nic check CRCs of frames in Rx;
- accept broadcast, multicast, phys match, all packets with dest addr (IFF Promiscuos mode enabled)
- set no Rx FIFO threshold, set unlimited DMA burst size*)
- s := SYSTEM.VAL(SET, Read32(44H));
- s := (s * {7, 11..12, 17..31}) + {1..3, 9, 14..15, 16};
- IF Promisc THEN
- INCL(s, 0);
- END;
- Write32(44H, SYSTEM.VAL(LONGINT, s));
- (* set multicast filter: receive everything *)
- Write32(08H, LONGINT(0FFFFFFFFH));
- Write32(08H + 4, LONGINT(0FFFFFFFFH));
- END ConfigRx;
- PROCEDURE SetTimer(val: LONGINT);
- BEGIN
- Write32(58H, val);
- END SetTimer;
- PROCEDURE GetHardwareVersion;
- VAR s: SET;
- BEGIN
- s := SYSTEM.VAL(SET, Read32(40H));
- s := s * {23, 26..30};
- IF DebugHWVer IN Debug THEN
- KernelLog.String("Hardware Version: ");
- END;
- IF s = {} THEN
- dev.hw := RTL8169;
- IF DebugHWVer IN Debug THEN
- KernelLog.String("RTL8169");
- END;
- ELSIF ((s * {23, 26}) # {}) & ((s * {27..30}) = {}) THEN
- dev.hw := RTL8169S;
- IF DebugHWVer IN Debug THEN
- KernelLog.String("RTL8169S/RTL8110S");
- END;
- ELSE
- dev.hw := UnknownHW;
- IF DebugHWVer IN Debug THEN
- KernelLog.String("Hardware Version is unknown");
- END;
- END;
- IF DebugHWVer IN Debug THEN
- KernelLog.Ln;
- END;
- END GetHardwareVersion;
- PROCEDURE ResetNIC;
- VAR s: SET;
- BEGIN
- Write8(37H, SYSTEM.VAL(LONGINT, {4}));
- (* wait until reset has finished *)
- REPEAT
- Delay(10);
- s := SYSTEM.VAL(SET, Read8(37H));
- UNTIL ~(4 IN s);
- END ResetNIC;
- PROCEDURE EnableTxRx(tx, rx: BOOLEAN);
- VAR s: SET;
- BEGIN
- s := SYSTEM.VAL(SET, Read8(37H));
- s := s * {0..1, 5..7};
- IF tx THEN
- INCL(s, 2);
- END;
- IF rx THEN
- INCL(s, 3);
- END;
- Write8(37H, SYSTEM.VAL(LONGINT, s));
- END EnableTxRx;
- PROCEDURE ReadMACAddress;
- VAR
- i: INTEGER;
- res: WORD;
- BEGIN
- (* MAC address is in registers 00H - 05H *)
- IF DebugMAC IN Debug THEN
- KernelLog.String("MAC address is: ");
- END;
- FOR i := 0 TO 5 DO
- res := Read8(i);
- SYSTEM.PUT8(ADDRESSOF(dev.local[i]), res);
- IF DebugMAC IN Debug THEN
- IF i > 0 THEN
- KernelLog.String("-");
- END;
- KernelLog.Hex(ORD(dev.local[i]), -2);
- END;
- END;
- IF DebugMAC IN Debug THEN
- KernelLog.Ln;
- END;
- dev.adrSize := 6;
- END ReadMACAddress;
- PROCEDURE Read8(reg: LONGINT): SHORTINT;
- BEGIN
- RETURN SYSTEM.GET8(base + reg);
- END Read8;
- PROCEDURE Write8(reg: LONGINT; val: LONGINT);
- BEGIN
- SYSTEM.PUT8(base + reg, SHORT(SHORT(val)));
- END Write8;
- PROCEDURE Read16(reg: LONGINT): INTEGER;
- BEGIN
- RETURN SYSTEM.GET16(base + reg);
- END Read16;
- PROCEDURE Write16(reg: LONGINT; val: LONGINT);
- BEGIN
- SYSTEM.PUT16(base + reg, SHORT(val));
- END Write16;
- PROCEDURE Read32(reg: LONGINT): LONGINT;
- BEGIN
- RETURN SYSTEM.GET32(base + reg);
- END Read32;
- PROCEDURE Write32(reg: LONGINT; val: LONGINT);
- BEGIN
- SYSTEM.PUT32(base + reg, val);
- END Write32;
- PROCEDURE EnableTBI;
- VAR
- s: SET;
- i: LONGINT;
- BEGIN
- IF 7 IN SYSTEM.VAL(SET, Read8(6CH)) THEN RETURN END;
- s := PHYRead(04H) + {5..8}; (* advertise 10 full/half, 100 full/half *)
- PHYWrite(04H, s);
- PHYWrite(09H, {9}); (* advertise 1000 full *)
- (* enable and restart auto negotiation *)
- PHYWrite(00H, {9, 12});
- Delay(100);
- FOR i := 1 TO 1000 DO
- s := PHYRead(01H);
- IF 5 IN s THEN (* auto negotiation complete *)
- Delay(100);
- IF DebugStatus IN Debug THEN
- PrintStatus;
- END;
- RETURN;
- ELSE
- Delay(100);
- END;
- END;
- END EnableTBI;
- PROCEDURE HwReset;
- VAR
- s: SET;
- i: LONGINT;
- BEGIN
- s := PHYRead(00H) + {15};
- PHYWrite(00H, s);
- (* wait until reset has been completet *)
- FOR i := 1 TO 50 DO
- IF ~(15 IN PHYRead(00H)) THEN
- RETURN;
- END;
- END;
- END HwReset;
- PROCEDURE PHYWrite(regAdr: LONGINT; data: SET);
- VAR
- s: SET;
- i: LONGINT;
- BEGIN
- s := {31};
- s := s + (SYSTEM.VAL(SET, regAdr * 010000H) * {16..20});
- s := s + (data * {0..15});
- Write32(60H, SYSTEM.VAL(LONGINT, s));
- Delay(100);
- (* wait until write has been completet *)
- FOR i := 1 TO 2000 DO
- IF SYSTEM.VAL(SET, Read32(60H)) * {31} = {} THEN
- RETURN;
- END;
- Delay(100);
- END;
- END PHYWrite;
- PROCEDURE PHYRead(regAdr: LONGINT): SET;
- VAR
- s: SET;
- i: LONGINT;
- BEGIN
- s := SYSTEM.VAL(SET, regAdr * 010000H) * {16..20};
- Write32(60H, SYSTEM.VAL(LONGINT, s));
- Delay(100);
- (* wait until read has been completed *)
- FOR i := 1 TO 2000 DO
- s := SYSTEM.VAL(SET, Read32(60H));
- IF 31 IN s THEN
- RETURN (s * {0..15});
- END;
- Delay(100);
- END;
- RETURN {};
- END PHYRead;
- PROCEDURE AllocBuffer(VAR buf: TxBuffer);
- BEGIN
- NEW(buf); (* edit: no more alignment necessary, since PTR TO RECORD is already 32 byte aligned *)
- END AllocBuffer;
- PROCEDURE SetupRxRing(): Machine.Address32;
- VAR
- r: LONGINT;
- adr, physAdr: ADDRESS;
- buf, prev: RxBuffer;
- BEGIN
- (* make sure the descriptor ring is 256 byte aligned in physical memory *)
- adr := ADDRESSOF(rds[0]);
- adr := Machine.PhysicalAdr(adr, SizeOfRxTxFDHdr);
- IF adr MOD 256 = 0 THEN
- firstRD := 0;
- ELSE
- firstRD := 16 - (LONGINT (adr MOD 256) DIV 16);
- END;
- IF DebugRxRing IN Debug THEN
- KernelLog.String("Rx descriptor start = ");
- KernelLog.Hex(adr, 8);
- KernelLog.Ln;
- KernelLog.String("first Rx descriptor id = ");
- KernelLog.Int(firstRD, 0);
- KernelLog.Ln;
- END;
- FOR r := firstRD TO RxRingSize - 1 DO
- NEW(buf);
- buf.buf := Network.GetNewBuffer();
- ASSERT(buf.buf # NIL);
- adr := ADDRESSOF(buf.buf.data[0]);
- physAdr := Machine.PhysicalAdr(adr, Network.MaxPacketSize);
- ASSERT(physAdr # Machine.NilAdr);
- rds[r].flags := {31};
- rds[r].flags := rds[r].flags + (SYSTEM.VAL(SET, Network.MaxPacketSize) * {0..13});
- rds[r].vLanTag := 0;
- rds[r].bufAdrLo := Machine.Ensure32BitAddress (physAdr);
- rds[r].bufAdrHi := 0;
- IF prev # NIL THEN
- prev.next := buf;
- ELSE
- (* set first Rx Buffer *)
- rxBuffer := buf;
- END;
- prev := buf;
- END;
- rxLast := buf;
- rxLast.next := rxBuffer;
- (* mark last descriptor as EOR (end of descriptor ring) *)
- INCL(rds[RxRingSize - 1].flags, 30);
- curRD := firstRD;
- adr := ADDRESSOF(rds[firstRD]);
- (* return physical address of first rx descriptor *)
- RETURN Machine.Ensure32BitAddress (Machine.PhysicalAdr(adr, SizeOfRxTxFDHdr));
- END SetupRxRing;
- PROCEDURE SetupTxRing(): Machine.Address32;
- VAR
- r: LONGINT;
- adr, physAdr: ADDRESS;
- buf, prev: TxBuffer;
- BEGIN
- (* make sure the descriptor ring is 256 byte aligned in physical memory *)
- adr := ADDRESSOF(tds[0]);
- adr := Machine.PhysicalAdr(adr, SizeOfRxTxFDHdr);
- IF adr MOD 256 = 0 THEN
- firstTD := 0;
- ELSE
- firstTD := 16 - (LONGINT (adr MOD 256) DIV 16);
- END;
- lastTD := firstTD;
- nofFreeTx := TxRingSize - firstTD;
- IF DebugTxRing IN Debug THEN
- KernelLog.String("Tx descriptor start = ");
- KernelLog.Hex(adr, -8);
- KernelLog.Ln;
- KernelLog.String("first Tx descriptor id = ");
- KernelLog.Int(firstTD, 0);
- KernelLog.Ln;
- KernelLog.String("nofFreeTx = ");
- KernelLog.Int(nofFreeTx, 0);
- KernelLog.Ln;
- END;
- FOR r := firstTD TO TxRingSize - 1 DO
- AllocBuffer(buf);
- (* configure TFD *)
- adr := ADDRESSOF(buf.data[0]);
- physAdr := Machine.PhysicalAdr(adr, TxMaxSize);
- ASSERT(physAdr # Machine.NilAdr);
- tds[r].flags := {};
- tds[r].vLanTag := 0;
- tds[r].bufAdrLo := Machine.Ensure32BitAddress (physAdr);
- tds[r].bufAdrHi := 0;
- IF prev # NIL THEN
- prev.next := buf;
- ELSE
- (* set first Tx Buffer *)
- txBuffer := buf;
- END;
- prev := buf;
- END;
- txLast := buf;
- txLast.next := txBuffer;
- (* mark last descriptor as EOR (end of descriptor ring) *)
- INCL(tds[TxRingSize - 1].flags, 30);
- curTD := firstTD;
- adr := ADDRESSOF(tds[firstTD]);
- (* return physical address of first tx descriptor *)
- RETURN Machine.Ensure32BitAddress (Machine.PhysicalAdr(adr, SizeOfRxTxFDHdr));
- END SetupTxRing;
- PROCEDURE ReadFrames;
- VAR
- adr: ADDRESS; type, size: LONGINT;
- dstAdr: Network.LinkAdr;
- buf: Network.Buffer;
- s: SET;
- BEGIN
- (* read all frames that are marked with OWN = 0*)
- WHILE ~(31 IN rds[curRD].flags) DO
- (* skip error frames *)
- IF (21 IN rds[curRD].flags) THEN
- INC(nRxErrorFrames);
- ELSIF CheckChecksumErrors(rds[curRD]) THEN
- (* find out how many bytes have been received, including CRC *)
- size := SYSTEM.VAL(LONGINT, rds[curRD].flags * {0..13});
- IF DebugReceive IN Debug THEN
- KernelLog.String("Received a frame of length ");
- KernelLog.Int(size, 0);
- KernelLog.Ln;
- END;
- adr := ADDRESSOF(rxBuffer.buf.data[0]);
- (* copy destination and source addresses, type of packet *)
- dstAdr := SYSTEM.VAL(Network.LinkAdr, rxBuffer.buf.data[0]);
- rxBuffer.buf.src := SYSTEM.VAL(Network.LinkAdr, rxBuffer.buf.data[6]);
- type := Network.GetNet2(rxBuffer.buf.data, 12);
- buf := rxBuffer.buf;
- buf.ofs := 14;
- buf.len := size - 14;
- buf.calcChecksum := { Network.ChecksumIP, Network.ChecksumUDP, Network.ChecksumTCP };
- buf.next := NIL;
- buf.prev := NIL;
- IF type = 0DEADH THEN
- (* make sure the frame doesn't bounce between the two cards by adding 1 to the type *)
- SendFrame(buf.src, type + 1, buf.data, buf.data, buf.data, 0, 0, 0, buf.len);
- ELSIF type = 0DEADH + 1 THEN
- (* discard this frame *)
- ELSE
- dev.QueueBuffer(buf, type);
- END;
- INC(nRxFrames);
- IF (type # 0DEADH) & (type # 0DEADH + 1) THEN
- rxBuffer.buf := Network.GetNewBuffer();
- buf := rxBuffer.buf;
- ASSERT(rxBuffer.buf # NIL);
- IF buf # NIL THEN
- rds[curRD].bufAdrLo := Machine.Ensure32BitAddress (Machine.PhysicalAdr(ADDRESSOF(rxBuffer.buf.data[0]), Network.MaxPacketSize));
- END;
- END;
- ELSE
- IF DebugReceive IN Debug THEN
- KernelLog.String("Checksum error detected!"); KernelLog.Ln;
- END;
- INC(nRxErrorFrames);
- END;
- (* mark the buffer to be able to receive again *)
- rds[curRD].flags := {31} + (rds[curRD].flags * {30}) + (SYSTEM.VAL(SET, Network.MaxPacketSize) * {0..13});
- rds[curRD].vLanTag := 0;
- s := rds[curRD].flags;
- (* advance Rx descriptor, Rx buffer *)
- rxBuffer := rxBuffer.next;
- INC(curRD);
- IF curRD = RxRingSize THEN
- curRD := firstRD;
- END;
- END;
- END ReadFrames;
- PROCEDURE CheckChecksumErrors(d: RxTxDescriptor): BOOLEAN;
- VAR proto: SET;
- BEGIN
- proto := d.flags * {17..18};
- IF proto = {} THEN
- RETURN TRUE; (* no checksum errors since non-ip packet *)
- ELSIF proto = {17} THEN
- (* protocol is TCP/IP so check IP and TCP checksum failures *)
- RETURN d.flags * {14, 16} = {};
- ELSIF proto = {18} THEN
- (* protocol is UDP/IP so check IP and UDP checksum failures *)
- RETURN d.flags * {15, 16} = {};
- ELSE
- (* protocol is IP so check IP checksum failures *)
- RETURN d.flags * {16} = {};
- END;
- END CheckChecksumErrors;
- PROCEDURE HandleInterrupt;
- VAR
- status, ack: SET;
- BEGIN
- (* get current interrupt mask, disable all interrupts *)
- Write16(3CH, 0);
- ack := {0};
- (* read interrupt status, @ offset 3EH - 3FH *)
- status := SYSTEM.VAL(SET, Read16(3EH));
- (* System Error (SERR) *)
- IF (15 IN InterruptMask) & (15 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- KernelLog.String("System Error Interrupt"); KernelLog.Ln;
- END;
- INCL(ack, 15);
- END;
- (* Time Out (TimeOut) *)
- IF (14 IN InterruptMask) & (14 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- KernelLog.String("Timeout Interrupt"); KernelLog.Ln;
- END;
- INCL(ack, 14);
- END;
- IF (8 IN InterruptMask) & (8 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- KernelLog.String("Software Interrupt"); KernelLog.Ln;
- END;
- INCL(ack, 8);
- END;
- IF (7 IN InterruptMask) & (7 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- KernelLog.String("Tx Descriptor Unavailable Interrupt"); KernelLog.Ln;
- END;
- INCL(ack, 7);
- (*UpdateTxRing;*)
- (*INCL(status, 2); (* let the tx ring be updated *)*)
- END;
- (* Rx FIFO Overflow (FOVW) *)
- IF (6 IN InterruptMask) & (6 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- KernelLog.String("Rx FIFO Overflow Interrupt"); KernelLog.Ln;
- END;
- INC(nRxOverflow);
- INCL(ack, 6);
- (*INCL(ack, 4);*)
- (*INCL(status, 0); (* read the frames *)*)
- END;
- (* Link Change (LinkChg) *)
- IF (5 IN InterruptMask) & (5 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- KernelLog.String("Link Change Interrupt"); KernelLog.Ln;
- END;
- UpdateLinkStatus;
- INCL(ack, 5);
- END;
- (* Rx Descriptor Unavailable (RDU) *)
- IF (4 IN InterruptMask) & (4 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- (* CAREFUL: UN-COMMENTING THE NEXT LINE CAN CRASH THE OS *)
- (*KernelLog.String("Rx Descriptor Unavailable Interrupt"); KernelLog.Ln;*)
- END;
- INCL(ack, 4);
- (*INCL(status, 0); (* read the frames *)*)
- END;
- (* Transmit (Tx) Error (TER) *)
- IF (3 IN InterruptMask) & (3 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- KernelLog.String("Transmit Error Interrupt"); KernelLog.Ln;
- END;
- INCL(ack, 3);
- INC(nTxErrorFrames);
- INCL(status, 2); (* let the tx ring be updated *)
- END;
- (* Transmit (Tx) OK (TOK) *)
- IF (2 IN InterruptMask) & (2 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- KernelLog.String("Transmit OK Interrupt"); KernelLog.Ln;
- END;
- UpdateTxRing;
- INCL(ack, 2);
- END;
- (* Receive (Rx) Error (RER) *)
- IF (1 IN InterruptMask) & (1 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- KernelLog.String("Receive Error Interrupt"); KernelLog.Ln;
- END;
- INCL(ack, 1);
- (*ReadFrames;*)
- INCL(status, 0); (* let the rx ring be updated *)
- END;
- (* Receive (Rx) OK (ROK) *)
- IF (0 IN InterruptMask) & (0 IN status) THEN
- IF DebugInterrupt IN Debug THEN
- (* CAREFUL: UN-COMMENTING THE NEXT LINE CAN CRASH THE OS *)
- (*KernelLog.String("Receive Ok Interrupt"); KernelLog.Ln;*)
- END;
- ReadFrames;
- INCL(ack, 0); (* read the frames *)
- END;
- ack := status;
- (* reset interrupt status *)
- Write16(3EH, SYSTEM.VAL(LONGINT, ack));
- (* re-enable interrupts *)
- Write16(3CH, SYSTEM.VAL(LONGINT, InterruptMask));
- END HandleInterrupt;
- PROCEDURE UpdateLinkStatus;
- BEGIN
- IF 1 IN SYSTEM.VAL(SET, Read8(6CH)) THEN
- linkStatus := Network.LinkLinked;
- ELSE
- linkStatus := Network.LinkNotLinked;
- END;
- END UpdateLinkStatus;
- PROCEDURE UpdateTxRing;
- VAR i: LONGINT;
- BEGIN { EXCLUSIVE }
- i := lastTD;
- WHILE (i # curTD) DO
- IF DebugTransmit IN Debug THEN
- KernelLog.String("*** Tx OK ***"); KernelLog.Ln;
- END;
- INC(i);
- INC(nTxFrames);
- INC(nofFreeTx);
- IF i = TxRingSize THEN
- i := firstTD;
- END;
- txLast := txLast.next;
- END;
- lastTD := i;
- END UpdateTxRing;
- PROCEDURE Finalize;
- VAR
- s: SET;
- BEGIN
- (* cleanup Network registry *)
- Network.registry.Remove(dev);
- (* disable Tx and Rx *)
- s := SYSTEM.VAL(SET, Read8(37H));
- Write8(37H, SYSTEM.VAL(SHORTINT, s - {2, 3}));
- (* soft reset *)
- Write8(37H, SYSTEM.VAL(SHORTINT, {4}));
- (* disable all interrupts *)
- Write16(3CH, 0);
- WHILE (rxBuffer # NIL) & (rxBuffer.buf # NIL) DO
- Network.ReturnBuffer(rxBuffer.buf);
- rxBuffer.buf := NIL;
- rxBuffer := rxBuffer.next;
- END;
- IF DebugCleanup IN Debug THEN
- KernelLog.String("Removing IRQ Handler.");
- KernelLog.Ln
- END;
- Objects.RemoveHandler(SELF.HandleInterrupt, Machine.IRQ0 + irq);
- END Finalize;
- PROCEDURE DebugConfig;
- VAR
- s: SET;
- res: WORD;
- BEGIN
- KernelLog.String("*** BEGIN OF NIC CONFIGURATION ***"); KernelLog.Ln;
- s := SYSTEM.VAL(SET, Read16(0E0H));
- KernelLog.String("C+ Command:"); KernelLog.Ln;
- KernelLog.String(" "); KernelLog.Bits(s, 0, 16); KernelLog.Ln;
- KernelLog.String("Rx Descriptor base address:"); KernelLog.Ln;
- KernelLog.String(" ");
- res := Read32(0E4H + 4H);
- KernelLog.Hex(res, 8);
- res := Read32(0E4H);
- KernelLog.Hex(res, 8);
- KernelLog.Ln;
- KernelLog.String("Tx Normal Priority Descriptor base address:"); KernelLog.Ln;
- KernelLog.String(" ");
- res := Read32(020H + 4H);
- KernelLog.Hex(res, 8);
- res := Read32(020H);
- KernelLog.Hex(res, 8);
- KernelLog.Ln;
- res := Read16(0DAH);
- KernelLog.String("Receive Packet Max Size:"); KernelLog.Ln;
- KernelLog.String(" "); KernelLog.Int(res, 0); KernelLog.Ln;
- res := Read8(0ECH);
- KernelLog.String("Max Transmit Packet Size:"); KernelLog.Ln;
- KernelLog.String(" "); KernelLog.Int(res * 32, 0); KernelLog.Ln;
- s := SYSTEM.VAL(SET, Read32(40H));
- KernelLog.String("Transmit Configuration:"); KernelLog.Ln;
- KernelLog.String(" "); KernelLog.Bits(s, 0, 32); KernelLog.Ln;
- s := SYSTEM.VAL(SET, Read32(44H));
- KernelLog.String("Receive Configuration:"); KernelLog.Ln;
- KernelLog.String(" "); KernelLog.Bits(s, 0, 32); KernelLog.Ln;
- s := SYSTEM.VAL(SET, Read16(3CH));
- KernelLog.String("interrupt mask:"); KernelLog.Ln;
- KernelLog.String(" "); KernelLog.Bits(s, 0, 16); KernelLog.Ln;
- s := SYSTEM.VAL(SET, Read8(37H));
- KernelLog.String("command bits:"); KernelLog.Ln;
- KernelLog.String(" "); KernelLog.Bits(s, 0, 8); KernelLog.Ln;
- KernelLog.String("*** END OF NIC CONFIGURATION ***"); KernelLog.Ln;
- END DebugConfig;
- PROCEDURE PrintStatus;
- VAR
- phyStatus: SET;
- BEGIN
- phyStatus := SYSTEM.VAL(SET, Read8(6CH));
- IF 1 IN phyStatus THEN
- KernelLog.String(" Device is linked");
- KernelLog.Ln;
- ELSE
- KernelLog.String(" Device is NOT linked");
- KernelLog.Ln;
- END;
- IF 4 IN phyStatus THEN
- KernelLog.String(" Linkspeed is 1GBps Full-Duplex");
- KernelLog.Ln;
- ELSE
- IF 3 IN phyStatus THEN
- KernelLog.String(" Linkspeed is 100MBps");
- KernelLog.Ln;
- ELSIF 2 IN phyStatus THEN
- KernelLog.String(" Linkspeed is 10MBps");
- KernelLog.Ln;
- END;
- IF 0 IN phyStatus THEN
- KernelLog.String(" Device is in FULL-DUPLEX MODE");
- KernelLog.Ln;
- ELSE
- KernelLog.String(" Device is in Half-Duplex Mode");
- KernelLog.Ln;
- END;
- END;
- IF 6 IN phyStatus THEN
- KernelLog.String(" Transmit Flow Control enabled");
- KernelLog.Ln;
- END;
- IF 5 IN phyStatus THEN
- KernelLog.String(" Receive Flow Control enabled");
- KernelLog.Ln;
- END;
- KernelLog.String(" nRxOverflow = ");
- KernelLog.HIntHex(nRxOverflow, 16);
- KernelLog.Ln;
- KernelLog.String(" nTxOverflow = ");
- KernelLog.HIntHex(nTxOverflow, 16);
- KernelLog.Ln;
- KernelLog.String(" Rx Missed Packet Counter = ");
- KernelLog.Int(Read32(4CH), 0);
- KernelLog.Ln;
- KernelLog.String(" nRxFrames = ");
- KernelLog.Int(nRxFrames, 0);
- KernelLog.Ln;
- KernelLog.String(" nTxFrames = ");
- KernelLog.Int(nTxFrames, 0);
- KernelLog.Ln;
- KernelLog.String(" nRxErrorFrames = ");
- KernelLog.Int(nRxErrorFrames, 0);
- KernelLog.Ln;
- KernelLog.String(" nTxErrorFrames = ");
- KernelLog.Int(nTxErrorFrames, 0);
- KernelLog.Ln;
- END PrintStatus;
- END Controller;
- VAR
- installedControllers: Controller;
- (* Scan the PCI bus for the specified card. *)
- PROCEDURE ScanPCI(vendor, device: LONGINT);
- VAR index, bus, dev, fct, irq, i: LONGINT; res: WORD; base: ADDRESS; d: LinkDevice; c: Controller; name: Plugins.Name;
- BEGIN
- index := 0;
- WHILE (PCI.FindPCIDevice(device, vendor, index, bus, dev, fct) = PCI.Done) & (installed < 16) DO
- res := PCI.ReadConfigDword(bus, dev, fct, PCI.Adr1Reg, i); ASSERT(res = PCI.Done);
- base := i; ASSERT(~ODD(base)); (* memory mapped *)
- DEC(base, base MOD 16);
- Machine.MapPhysical(base, 0FFH, base);
- res := PCI.ReadConfigByte(bus, dev, fct, PCI.IntlReg, irq); ASSERT(res = PCI.Done);
- NEW(d, Network.TypeEthernet, MaxETHFrameSize - 14, 6);
- name := Name;
- i := 0; WHILE name[i] # 0X DO INC(i) END;
- IF installed > 9 THEN
- name[i] := CHR(ORD("A") + installed - 10);
- ELSE
- name[i] := CHR(ORD("0") + installed);
- END;
- name[i+1] := 0X;
- IF DebugFind IN Debug THEN
- KernelLog.String("Found device: ");
- KernelLog.String(name);
- KernelLog.String("; IRQ = ");
- KernelLog.Int(irq, 0);
- KernelLog.Ln;
- END;
- d.SetName(name);
- d.desc := Description;
- NEW(c, d, base, irq); (* increments "installed" when successful *)
- IF DebugStatus IN Debug THEN
- c.PrintStatus;
- END;
- INC(index)
- END
- END ScanPCI;
- PROCEDURE Install*;
- BEGIN {EXCLUSIVE}
- IF DebugFind IN Debug THEN
- KernelLog.String("Searching devices...");
- KernelLog.Ln
- END;
- IF installed = 0 THEN
- ScanPCI(10ECH, 8169H); (* Vendor = RealTek, Device = RTL8169 *)
- END;
- IF DebugFind IN Debug THEN
- KernelLog.String("Find finished.");
- KernelLog.Ln
- END;
- END Install;
- PROCEDURE DebugStati*;
- VAR c: Controller;
- BEGIN
- c := installedControllers;
- WHILE c # NIL DO
- c.PrintStatus;
- c := c.next;
- END;
- END DebugStati;
- PROCEDURE TestDevices*;
- VAR c: Controller;
- BEGIN
- c := installedControllers;
- WHILE c # NIL DO
- TestDevice(c);
- c := c.next;
- END;
- END TestDevices;
- PROCEDURE TestDevice(ctrl: Controller);
- VAR
- i, diff, bytes, times: LONGINT;
- milliTimer : Kernel.MilliTimer;
- data: ARRAY 1024 OF CHAR;
- bw: REAL;
- dst: Network.LinkAdr;
- BEGIN
- dst[0] := 000X;
- dst[1] := 030X;
- dst[2] := 04FX;
- dst[3] := 025X;
- dst[4] := 0BBX;
- dst[5] := 0DBX;
- IF ctrl # NIL THEN
- ctrl.nRxFrames := 0;
- ctrl.nTxFrames := 0;
- (* fill the buffer *)
- FOR i := 0 TO LEN(data)-1 DO
- data[i] := CHR(i MOD 100H)
- END;
- Kernel.SetTimer(milliTimer, 0);
- times := 1024 * 1024 * 2;
- FOR i := 1 TO times DO
- ctrl.SendFrame(dst, 0DEADH, data, data, data, 0, 0, 0, LEN(data));
- IF i MOD 1024 = 0 THEN
- Delay(1);
- END;
- END;
- diff := Kernel.Elapsed(milliTimer);
- times := ctrl.nRxFrames * 2;
- bytes := (LEN(data));
- KernelLog.String("stats:"); KernelLog.Ln;
- KernelLog.String("frame size = ");
- KernelLog.Int(bytes, 0);
- KernelLog.String("; num frames = ");
- KernelLog.Int(times, 0);
- KernelLog.String("; time = ");
- KernelLog.Int(diff, 0); KernelLog.String("ms");
- KernelLog.String("; bandwidth = ");
- bw := bytes * 1.0 * times / (diff / 1000.0);
- KernelLog.Int(ENTIER(bw / 1024), 0); KernelLog.String("KB/s, ");
- KernelLog.Int(ENTIER(bw * 8 / 1000 / 1000), 0); KernelLog.String("Mbps"); KernelLog.Ln;
- END
- END TestDevice;
- PROCEDURE Cleanup;
- BEGIN
- WHILE installedControllers # NIL DO
- IF DebugCleanup IN Debug THEN
- KernelLog.Ln;
- KernelLog.String("Removing ");
- KernelLog.String(installedControllers.dev.name);
- KernelLog.Ln;
- installedControllers.PrintStatus;
- END;
- installedControllers.Finalize;
- installedControllers := installedControllers.next;
- IF DebugCleanup IN Debug THEN
- KernelLog.String("Success!");
- KernelLog.Ln;
- END;
- END;
- installedControllers := NIL;
- END Cleanup;
- PROCEDURE Delay(ms: LONGINT);
- VAR
- t: Kernel.MilliTimer;
- BEGIN
- Kernel.SetTimer(t, ms);
- REPEAT UNTIL Kernel.Expired(t);
- END Delay;
- BEGIN
- Modules.InstallTermHandler(Cleanup);
- END RTL8169.
- (*
- MAC address 00-30-4F-25-BB-DB
- MAC address 00-08-A1-3C-06-CB
- local IP 129.132.134.209
- System.Free RTL8169 ~
- RTL8169.Install ~
- WMPerfMon.Open ~
- RTL8169.DebugStati ~
- IP.IPConfig ~
- RTL8169.TestDevices~
- OFSTools.Mount RAM RamFS 300000 4096 ~
- TestNet.SetDevice "RTL8169#0" ~
- TestNet.ShowDevices ~
- TestNet.SendBroadcast ~
- TestNet.SendBroadcastVar 1499 ~
- TestNet.SendTest ^ 1 10 100 1000 ~
- *)
|