MODULE AM79C970;
IMPORT
SYSTEM, Machine, PCI, Objects, Modules, Plugins, Network, KernelLog;
CONST
Name = "AM79C970#";
Description = "AMD Network Driver, Chipversion AM79C970A";
MaxETHFrameSize = 1514;
TxBufSize = 1600;
RxBufSize =1536;
RxRingSize = 32;
TxRingSize = 16;
ModeDRX = 0;
ModeDTX = 1;
ModePROM = 15;
RAP=12H;
RDP=10H;
BDP=16H;
RESET=14H;
CSR0 = 0;
OWN = 31;
VAR
installed: LONGINT;
installFinished: BOOLEAN;
outPackets, inPackets, missedFrames: LONGINT;
TYPE
InitializationBlock = RECORD
modeTlenRlen : SET;
padr : ARRAY 3 OF INTEGER;
reserved : INTEGER;
ladr : ARRAY 2 OF SET;
rdra : Machine.Address32;
tdra : Machine.Address32;
END;
TxBuffer = POINTER TO ARRAY TxBufSize OF CHAR;
LinkDevice = OBJECT (Network.LinkDevice)
VAR
ctrl: Controller;
hw: LONGINT;
PROCEDURE Linked*(): LONGINT;
BEGIN
IF ctrl.Linked() THEN
RETURN Network.LinkLinked;
ELSE
RETURN Network.LinkNotLinked;
END;
END Linked;
PROCEDURE DoSend*(dst: Network.LinkAdr; type: LONGINT; VAR l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
VAR
i, pos: LONGINT;
tBuf: TxBuffer;
flags1: SET;
BEGIN
INC(outPackets);
tBuf := ctrl.txBufRing[ctrl.txIndex];
ctrl.DisableInterrupts();
pos := 0;
FOR i := 0 TO 6 - 1 DO tBuf[pos + i] := dst[i] END;
INC(pos, 6);
FOR i := 0 TO 6 - 1 DO tBuf[pos + i] := local[i] END;
INC(pos, 6);
tBuf[pos] := CHR(type DIV 100H);
INC(pos);
tBuf[pos] := CHR(type MOD 100H);
INC(pos);
FOR i := 0 TO h3len - 1 DO
tBuf[pos+i] := l3hdr[i]
END;
INC(pos, h3len);
FOR i := 0 TO h4len - 1 DO
tBuf[pos + i] := l4hdr[i]
END;
INC(pos, h4len);
FOR i := 0 TO dlen - 1 DO
tBuf[pos + i] := data[i + dofs];
END;
INC(pos, dlen);
flags1 := SYSTEM.VAL(SET, -pos) - {16..31} + {OWN} + {25, 24};
SYSTEM.PUT32(ctrl.txRingAdr + ctrl.txIndex * 16 + 4, flags1);
ctrl.txIndex:=(ctrl.txIndex+1) MOD TxRingSize;
ctrl.WriteCSR(0,58);
ctrl.EnableInterrupts();
END DoSend;
PROCEDURE Finalize(connected: BOOLEAN);
BEGIN
ctrl.Finalize;
Finalize^(connected);
END Finalize;
END LinkDevice;
Controller = OBJECT
VAR
next: Controller;
base, irq: LONGINT;
dev: LinkDevice;
initBlock: InitializationBlock;
rxAlignDescriptorRing: POINTER TO ARRAY (RxRingSize+1)*16 OF CHAR;
txAlignDescriptorRing: POINTER TO ARRAY (TxRingSize+1)*16 OF CHAR;
rxRingAdr: SYSTEM.ADDRESS;
txRingAdr: SYSTEM.ADDRESS;
txBufRing: ARRAY TxRingSize OF TxBuffer;
rxBufRing: ARRAY RxRingSize OF Network.Buffer;
rxIndex, txIndex : LONGINT;
PROCEDURE &Init*(dev: LinkDevice; base, irq: LONGINT);
VAR
res: LONGINT;
s: SET;
i,x: INTEGER;
BEGIN
outPackets:=0;
inPackets:=0;
missedFrames:= 0;
FOR i := 0 TO 5 DO dev.broadcast[i] := 0FFX END;
SELF.next := installedControllers;
installedControllers := SELF;
SELF.base := base;
SELF.dev := dev;
SELF.irq := irq;
dev.ctrl := SELF;
IF (irq >= 1) & (irq <= 15) THEN
Objects.InstallHandler(SELF.HandleInterrupt, Machine.IRQ0+irq);
END;
Machine.Portin16(base + RESET, x);
ASSERT(ReadCSR(0)=4);
ASSERT(DeviceOk());
initBlock.modeTlenRlen := {ModePROM, ModeDTX, ModeDRX};
initBlock.modeTlenRlen := initBlock.modeTlenRlen + {30} + {22} + {20};
Machine.Portin16(base, x);
dev.local[0] := CHR(x MOD 100H);
dev.local[1] := CHR(x DIV 100H);
initBlock.padr[0] := x;
Machine.Portin16(base + 2, x);
dev.local[2] := CHR(x MOD 100H);
dev.local[3] := CHR(x DIV 100H);
initBlock.padr[1] := x;
Machine.Portin16(base + 4, x);
dev.local[4] := CHR(x MOD 100H);
dev.local[5] := CHR(x DIV 100H);
initBlock.padr[2] := x;
initBlock.ladr[0] := SYSTEM.VAL(SET, 0H);
initBlock.ladr[1] := SYSTEM.VAL(SET, 0H);
NEW(rxAlignDescriptorRing);
rxRingAdr := SYSTEM.ADR(rxAlignDescriptorRing[0]);
IF rxRingAdr MOD 16 # 0 THEN
INC(rxRingAdr, 16 - rxRingAdr MOD 16);
END;
initBlock.rdra := Machine.Ensure32BitAddress (rxRingAdr);
NEW(txAlignDescriptorRing);
txRingAdr := SYSTEM.ADR(txAlignDescriptorRing[0]);
IF txRingAdr MOD 16 # 0 THEN
INC(txRingAdr, 16 - txRingAdr MOD 16);
END;
initBlock.tdra := Machine.Ensure32BitAddress (txRingAdr);
WriteBCR(20, 2);
s := SYSTEM.VAL(SET, SYSTEM.ADR(initBlock));
x := SYSTEM.VAL(INTEGER, SYSTEM.ADR(initBlock) MOD 10000H);
WriteCSR(1, x);
x:= SYSTEM.VAL(INTEGER, SYSTEM.ADR(initBlock) DIV 10000H);
WriteCSR(2, x);
WriteCSR(CSR0, 1);
i := 0;
REPEAT
INC(i)
UNTIL (8 IN SYSTEM.VAL(SET, ReadCSR(CSR0))) OR (i > 1000);
ASSERT( i < 1000) ;
WriteCSR(CSR0, 42H);
SetupRxTxRings();
Network.registry.Add(dev, res);
ASSERT(res = Plugins.Ok);
INC(installed);
END Init;
PROCEDURE ReadCSR(nr:INTEGER) : INTEGER;
VAR x: INTEGER;
BEGIN
Machine.Portout16(base + RAP, nr);
Machine.Portin16(base + RDP, x);
RETURN x;
END ReadCSR;
PROCEDURE WriteCSR(nr, val : INTEGER);
BEGIN
Machine.Portout16(base + RAP, nr);
Machine.Portout16(base + RDP, val);
END WriteCSR;
PROCEDURE ReadBCR(nr: INTEGER) : INTEGER;
VAR x : INTEGER;
BEGIN
Machine.Portout16(base + RAP, nr);
Machine.Portin16(base + BDP, x);
RETURN x;
END ReadBCR;
PROCEDURE WriteBCR(nr, val : INTEGER);
BEGIN
Machine.Portout16(base + RAP, nr);
Machine.Portout16(base + BDP, val);
END WriteBCR;
PROCEDURE DeviceOk() : BOOLEAN;
VAR x : INTEGER;
BEGIN
x := 88;
Machine.Portout16(base + RAP, x);
Machine.Portin16(base + RAP, x);
RETURN x = 88
END DeviceOk;
PROCEDURE SetupRxTxRings;
VAR
i: LONGINT;
adr: SYSTEM.ADDRESS;
t: SET;
rBuf: Network.Buffer;
tBuf: TxBuffer;
BEGIN
rxIndex := 0;
txIndex := 0;
adr := rxRingAdr;
FOR i:=0 TO RxRingSize-1 DO
rBuf:=Network.GetNewBuffer();
rxBufRing[i] := rBuf;
SYSTEM.PUT32(adr, SYSTEM.ADR(rBuf.data[0])); INC(adr, 4);
SYSTEM.PUT16(adr, -RxBufSize); INC(adr, 2);
SYSTEM.PUT16(adr, 8000H); INC(adr, 2);
SYSTEM.PUT32(adr, 0); INC(adr, 4);
SYSTEM.PUT32(adr, 0); INC(adr, 4)
END;
t:= SYSTEM.VAL(SET, 0FFFH-TxBufSize+1)+{12..15};
adr := txRingAdr;
FOR i:=0 TO TxRingSize-1 DO
NEW(tBuf);
txBufRing[i] := tBuf;
SYSTEM.PUT32(adr, SYSTEM.ADR(tBuf[0])); INC(adr, 4);
SYSTEM.PUT32(adr, t); INC(adr, 4);
SYSTEM.PUT32(adr, 0); INC(adr, 4);
SYSTEM.PUT32(adr, 0); INC(adr, 4)
END;
HWStop();
WriteCSR(15, 0);
WriteCSR(4, 915H);
HWStart();
END SetupRxTxRings;
PROCEDURE UpdateTxRing;
VAR
i:LONGINT;
flags1, flags2: SET;
BEGIN
i := 0;
WHILE i < TxRingSize DO
flags1 := SYSTEM.VAL(SET, SYSTEM.GET32(txRingAdr + i * 16 + 4));
flags2 := SYSTEM.VAL(SET, SYSTEM.GET32(txRingAdr + i * 16 + 8));
IF ~(31 IN flags1) THEN
SYSTEM.PUT32(txRingAdr+ i * 16+4,SYSTEM.VAL(SET, 0FFFH-TxBufSize+1)+{12..15});
SYSTEM.PUT32(txRingAdr+i*16+8, 0);
END;
INC(i);
END;
END UpdateTxRing;
PROCEDURE ReceivePacket;
VAR
type, size: LONGINT;
rBuf, buf: Network.Buffer;
flags1, flags2:SET;
BEGIN
DisableInterrupts();
flags1 := SYSTEM.VAL(SET,SYSTEM.GET32(rxRingAdr + rxIndex * 16 + 4));
flags2 := SYSTEM.VAL(SET,SYSTEM.GET32(rxRingAdr + rxIndex * 16 + 8));
WHILE ~(31 IN flags1) DO
INC(inPackets);
buf := Network.GetNewBuffer();
IF buf # NIL THEN
rBuf:=rxBufRing[rxIndex];
size:= SYSTEM.VAL(INTEGER,flags2);
type := Network.GetNet2(rBuf.data, 6 + 6);
rBuf.ofs:= 14;
rBuf.len:= size;
rBuf.src:= SYSTEM.VAL(Network.LinkAdr, rBuf.data[6]);
rBuf.calcChecksum:= {};
dev.QueueBuffer(rBuf, type);
rxBufRing[rxIndex]:=buf;
SYSTEM.PUT32(rxRingAdr+ rxIndex * 16, SYSTEM.ADR(buf.data[0]));
SYSTEM.PUT32(rxRingAdr+ rxIndex * 16+4,SYSTEM.VAL(SET, 0FFFH-RxBufSize+1)+{12..15}+{31});
SYSTEM.PUT32(rxRingAdr+ rxIndex * 16+8, 0);
ELSE
KernelLog.String("NO MORE BUFFERS!!!!!!!"); KernelLog.Ln;
END;
rxIndex:=(rxIndex+1) MOD RxRingSize;
flags1 := SYSTEM.VAL(SET,SYSTEM.GET32(rxRingAdr + rxIndex * 16 + 4));
flags2 := SYSTEM.VAL(SET,SYSTEM.GET32(rxRingAdr + rxIndex * 16 + 8));
END;
EnableInterrupts();
END ReceivePacket;
PROCEDURE HWStop;
BEGIN
WriteCSR(CSR0, 4);
END HWStop;
PROCEDURE HWStart;
BEGIN
WriteCSR(15, SYSTEM.VAL(INTEGER, {ModePROM}));
WriteCSR(CSR0, SYSTEM.VAL(INTEGER, {1, 6}))
END HWStart;
PROCEDURE DisableInterrupts;
VAR
x: INTEGER;
BEGIN
x:=ReadCSR(0);
WriteCSR(0, SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, x)-{6}-{14}-{13}-{12}-{11}-{10}-{9}));
END DisableInterrupts;
PROCEDURE EnableInterrupts;
VAR
x: INTEGER;
BEGIN
x:=ReadCSR(0);
WriteCSR(0, SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, x)+{6}-{14}-{13}-{12}-{11}-{10}-{9}));
END EnableInterrupts;
PROCEDURE HandleInterrupt;
VAR
status : INTEGER;
BEGIN
status:=ReadCSR( 0);
IF (9 IN SYSTEM.VAL(SET,status)) THEN
UpdateTxRing();
END;
IF (10 IN SYSTEM.VAL(SET,status)) THEN
ReceivePacket();
END;
IF (12 IN SYSTEM.VAL(SET,status)) THEN
INC(missedFrames);
END;
status:=ReadCSR(0);
WriteCSR(0, status);
END HandleInterrupt;
PROCEDURE Linked():BOOLEAN;
BEGIN
RETURN TRUE;
END Linked;
PROCEDURE Finalize;
BEGIN
Network.registry.Remove(dev);
DEC(installed);
Objects.RemoveHandler(SELF.HandleInterrupt, Machine.IRQ0 + irq);
END Finalize;
END Controller;
VAR
installedControllers: Controller;
PROCEDURE ScanPCI(vendor, device: LONGINT);
VAR
index, bus, dev, fct, res, base, irq, i: LONGINT;
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.Adr0Reg, base);
ASSERT (res = PCI.Done);
ASSERT(ODD(base));
DEC(base, base MOD 4);
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;
KernelLog.String("Found device: "); KernelLog.String(name); KernelLog.String("; IRQ = "); KernelLog.Int(irq, 0); KernelLog.Ln;
res:=PCI.WriteConfigDword(bus, dev, fct, PCI.CmdReg, 5);
d.SetName(name);
d.desc := Description;
NEW(c, d, base, irq);
INC(index);
END
END ScanPCI;
PROCEDURE Install*;
BEGIN {EXCLUSIVE}
IF installed = 0 THEN
ScanPCI(1022H, 2000H);
END;
END Install;
PROCEDURE Cleanup;
BEGIN
WHILE installedControllers # NIL DO
KernelLog.String("Removing "); KernelLog.String(installedControllers.dev.name); KernelLog.Ln;
installedControllers.Finalize;
installedControllers := installedControllers.next;
KernelLog.String("Outgoing packets: "); KernelLog.Int(outPackets,0); KernelLog.Ln;
KernelLog.String("Incoming packets: "); KernelLog.Int(inPackets,0); KernelLog.Ln;
KernelLog.String("Missed packets: "); KernelLog.Int(missedFrames,0); KernelLog.Ln;
KernelLog.String("Success!"); KernelLog.Ln;
END;
installedControllers := NIL;
END Cleanup;
BEGIN
installFinished:=FALSE;
Modules.InstallTermHandler(Cleanup);
END AM79C970.
(*
SystemTools.Free AM79C970~
AM79C970.Install ~
*)