123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602 |
- MODULE XEmac; (** AUTHOR "Timothee Martiel"; PURPOSE "Zynq7000 Ethernet Controller Driver"; *)
- (** 2014.08.26 Adapted the driver for Minos to A2 *)
- IMPORT SYSTEM, Machine, Objects, Kernel, KernelLog, Network;
- CONST
- Trace = FALSE;
- IRQ = 54;
- (* Directions in ErrorHandler *)
- Send = 1X;
- Recv = 2X;
- (* Link speed detect modes *)
- LinkSpeedAutodetect = 0;
- LinkSpeed10 = 1;
- LinkSpeed100 = 2;
- LinkSpeed1000 = 3;
- LinkSpeedMode = LinkSpeedAutodetect;
- (* state *)
- IsReady = 11111111H;
- IsStarted = 22222222H;
- (* Buffer descriptors *)
- BdSize = 8;
- RxBdCount = 512;
- TxBdCount = 512;
- BdAdrOffset = 0H;
- BdStatOffset = 4H;
- BufSize = 1536;
- ZeroMAC = SYSTEM.VAL(Network.LinkAdr, [0X, 0X, 0X, 0X, 0X, 0X, 0X, 0X]);
- MaxTypeId = 4;
- (* Options *)
- (**
- * Accept all incoming packets.
- * This option defaults to disabled (cleared)
- *)
- Promisc = 0;
- (**
- * Frame larger than 1516 support for Tx & Rx.
- * This option defaults to disabled (cleared)
- *)
- Frame1536 = 1;(* 00000002H; *)
- (**
- * VLAN Rx & Tx frame support.
- * This option defaults to disabled (cleared)
- *)
- Vlan = 2;(* 00000004H; *)
- (**
- * Enable recognition of flow control frames on Rx
- * This option defaults to enabled (set)
- *)
- FlowControl = 4;(* 00000010H; *)
- (**
- * Strip FCS and PAD from incoming frames. Note: PAD from VLAN frames is not
- * stripped.
- * This option defaults to enabled (set)
- *)
- FcsStrip = 5;(* 00000020H; *)
- (**
- * Generate FCS field and add PAD automatically for outgoing frames.
- * This option defaults to disabled (cleared)
- *)
- FcsInsert = 6;(* 00000040H; *)
- (**
- * Enable Length/TYPE error checking for incoming frames. When this option is
- * set, the MAC will filter frames that have a mismatched TYPE/length field
- * and if REPORT_RXERR is set, the user is notified when these
- * TYPEs of frames are encountered. When this option is cleared, the MAC will
- * allow these TYPEs of frames to be received.
- *
- * This option defaults to disabled (cleared)
- *)
- LenTypeErr = 7;(* 00000080H; *)
- (**
- * Enable the transmitter.
- * This option defaults to enabled (set)
- *)
- TransmitterEnable = 8;(* 00000100H; *)
- (**
- * Enable the receiver
- * This option defaults to enabled (set)
- *)
- ReceiverEnable = 9;(*00000200H *);
- (**
- * Allow reception of the broadcast address
- * This option defaults to enabled (set)
- *)
- Broadcast = 10;(* 00000400H; *)
- (**
- * Allows reception of multicast addresses programmed into hash
- * This option defaults to disabled (clear)
- *)
- Multicast = 11;(* 00000800H; *)
- (**
- * Enable the RX checksum offload
- * This option defaults to enabled (set)
- *)
- RxChksumEnable = 12;(* 00001000H; *)
- (**
- * Enable the TX checksum offload
- * This option defaults to enabled (set)
- *)
- TxChksumEnable = 13;(* 00002000H; *)
- Defaults = {Promisc, FlowControl, FcsInsert, FcsStrip, Broadcast, LenTypeErr, TransmitterEnable, ReceiverEnable, RxChksumEnable, TxChksumEnable};
- (* Register relative addresses *)
- Nwctrl = 0H;
- Nwcfg = 4H;
- Nwsr = 8H;
- Dmacr = 10H;
- Txsr = 14H;
- Rxqbase = 18H;
- Txqbase = 1CH;
- Rxsr = 20H;
- Isr = 24H;
- Ier = 28H;
- Idr = 2CH;
- Imr = 30H;
- PhyMntnc = 34H;
- Rxpause = 38H;
- Txpause = 3CH;
- HashL = 80H;
- HashH = 84H;
- Last = 1B4H;
- Laddr1l = 88H;
- Laddr1h = 8CH;
- Laddr2l = 90H;
- Laddr2h = 94H;
- Laddr3l = 98H;
- Laddr3h = 9CH;
- Laddr4l = 0A0H;
- Laddr4h = 0A4H;
- Match1 = 0A8H;
- Match2 = 0ACH;
- Match3 = 0B0H;
- Match4 = 0B4H;
- Stretch = 0BCH;
- OctTxL = 100H;
- OctTxH = 104H;
- Txcnt = 108H;
- Txbccnt = 10CH;
- Txmccnt = 110H;
- Txpausecnt = 114H;
- Tx64cnt = 118H;
- Tx65cnt = 11CH;
- Tx128cnt = 120H;
- Tx256cnt = 124H;
- Tx512cnt = 128H;
- Tx1024cnt = 12CH;
- Tx1519cnt = 130H;
- Txuruncnt = 134H;
- Snglcollcnt = 138H;
- Multicollcnt = 13CH;
- Excesscollcnt = 140H;
- Latecollcnt = 144H;
- Txdefercnt = 148H;
- Txcsensecnt = 14CH;
- Octrxl = 150H;
- Octrxh = 154H;
- Rxcnt = 158H;
- Rxbroadcnt = 15CH;
- Rxmulticnt = 160H;
- Rxpausecnt = 164H;
- Rx64cnt = 168H;
- Rx65cnt = 16CH;
- Rx128cnt = 170H;
- Rx256cnt = 174H;
- Rx512cnt = 178H;
- Rx1024cnt = 17CH;
- Rx1519cnt = 180H;
- Rxundrcnt = 184H;
- Rxovrcnt = 188H;
- Rxjabcnt = 18CH;
- Rxfcscnt = 190H;
- Rxlengthcnt = 194H;
- Rxsymbcnt = 198H;
- Rxaligncnt = 19CH;
- Rxreserrcnt = 1A0H;
- Rxorcnt = 1A4H;
- Rxipccnt = 1A8H;
- Rxtcpccnt = 1ACH;
- Rxudpccnt = 1B0H;
- C1588_sec = 1D0H;
- C1588_nanosec = 1D4H;
- C1588_adj = 1D8H;
- C1588_inc = 1DCH;
- Ptp_txsec = 1E0H;
- Ptp_txnanosec = 1E4H;
- Ptp_rxsec = 1E8H;
- Ptp_rxnanosec = 1ECH;
- Ptpp_txsec = 1F0H;
- Ptpp_txnanosec = 1F4H;
- Ptpp_rxsec = 1F8H;
- Ptpp_rxnanosec = 1FCH;
- (** Masks and bits *)
- DmacrRxBuf = {16 .. 23};
- DmacrRxBufShift = 16;
- DmacrTcpChksum = 11;
- DmacrTxSize = 10;
- DmacrRxSize = {8, 9};
- DmacrEndian = 7;
- DmacrBlength = {0 .. 4};
- DmacrSingleAhbBurst = 0;
- DmacrIncr4AhbBurst = 2;
- DmacrIncr8AhbBurst = 3;
- DmacrIncr16AhbBurst = 4;
- IxrPtppstx = 25;
- IxrPtppdrtx = 24;
- IxrPtpstx = 23;
- IxrPtpdrtx = 22;
- IxrPtppsrx = 21;
- IxrPtppdrrx = 20;
- IxrPtpsrx = 19;
- IxrPtpdrrx = 18;
- IxrPauseTx = 14;
- IxrPauseZero = 13;
- IxrPauseNzero = 12;
- IxrHrespnOk = 11;
- IxrRxOvr = 10;
- IxrTxCompl = 7;
- IxrTxExh = 6;
- IxrRetry = 5;
- IxrUrun = 4;
- IxrTxUsed = 3;
- IxrRxUsed = 2;
- IxrFrameRx = 1;
- IxrMgmnt = 0;
- IxrAll = {0 .. 14};
- IxrTxErr = {IxrTxExh, IxrRetry, IxrUrun, IxrTxUsed};
- IxrRxErr = {IxrHrespnOk, IxrRxUsed, IxrRxOvr};
- LaddrMach = {0 .. 31};
- NwcfgBadpreambEn = 29;
- NwcfgIpdStretch = 28;
- NwcfgFcsIgnore = 26;
- NwcfgHdRxEn = 25;
- NwcfgRxChkSumEn = 24;
- NwcfgPauseCopyDi = 23;
- NwcfgMdcShift = 18;
- NwcfgMdcClkDiv = {18 .. 20};
- NwcfgFcsRem = 17;
- NwcfgLengthErrDscrd = 16;
- Nwcfg1000 = 10;
- Nwcfg100 = 0;
- NwcfgUcastHashEn = 7;
- NwcfgFdEn = 1;
- Nwcfg1536RxEn = 8;
- NwcfgNvlanDisc = 2;
- NwcfgPauseEn = 13;
- NwcfgCopyAllEn = 4;
- NwcfgBcastDi = 5;
- NwcfgMcastHashEn = 6;
- NwctrlZeroPauseTx = {11};
- NwctrlPauseTx = {11};
- NwctrlHaltTx = {10};
- NwctrlStartTx = {9};
- NwctrlStatwen = {7};
- NwctrlStatinc = {6};
- NwctrlStatclr = {5};
- NwctrlMdEn = {4};
- NwctrlTxEn = {3};
- NwctrlRxEn = {2};
- NwctrlLoopEn = {1};
- NwsrMdio = 1;
- NwsrMdioIdle = 2;
- PhyMntncOp = {17, 30};
- PhyMntncOpR = {29};
- PhyMntncOpW = {28};
- PhyMntncAddR = {23 .. 27};
- PhyMntncReg = {18 .. 22};
- PhyMntncData = {0 .. 15};
- PhyMntncPhyAdShift = 23;
- PhyMntncPhRegShift = 18;
- RxsrHrespnok = 3;
- RxsrRxOvr = 2;
- RxsrFrameRx = 1;
- RxsrBuffna = 0;
- RxsrError = 13;
- RxBufBcast = 31;
- RxBufMultiHash = 30;
- RxBufUniHash = 29;
- RxBufExh = 28;
- RxBufAMatch = {25,26};
- RxBufIDfound = 24;
- RxBufIDmatch = {22,23};
- RxBufVlan = 21;
- RxBufPri = 20;
- RxBufVpri = {17..19};
- RxBufCfi = 16;
- RxBufEof = 15;
- RxBufSof = 14;
- RxBufLen = {0 .. 13};
- RxBufWrap = 1;
- RxBufNew = 0;
- RxBufAdd = {2 .. 31};
- RxBufSize = 1536;
- RxBufUnit = 64;
- TxBufUsed = 31;
- TxBufWrap = 30;
- TxBufRetry = 29;
- TxBufUrun = 28;
- TxBufExh = 27;
- TxBufTcp = 26;
- TxBufNocrc = 16;
- TxBufLast = 15;
- TxBufLen = {0 .. 13};
- TxsrHrespnok = 8;
- TxsrUrun = 6;
- TxsrTxCompl = 5;
- TxsrBufExh = 4;
- TxsrTxGo = 3;
- TxsrRxOvr = 2;
- TxsrFrameRx = 1;
- TxsrUsedRead = 0;
- TxsrError = {TxsrHrespnok, TxsrUrun, TxsrBufExh, TxsrRxOvr, TxsrFrameRx, TxsrUsedRead};
- (** Clock divisors *)
- MdcDiv8 = 0;
- MdcDiv16 = 1;
- MdcDiv32 = 2;
- MdcDiv48 = 3;
- MdcDiv64 = 4;
- MdcDiv96 = 5;
- MdcDiv128 = 6;
- MdcDiv224 = 7;
- (* Phy return state *)
- EmacMiiReadError = 1003;
- EmacMiiBusy = 1004;
- Success = 0;
- Failure = 1;
- DeviceIsStarted = 5;
- DeviceIsStopped = 6;
- (* Phy registers *)
- IeeeControlReg = 0;
- IeeeStatusReg = 1;
- IeeeAutonegoAdvertiseReg = 4;
- IeeePartnerAbilities1Reg = 5;
- Ieee1000AdvertiseReg = 9;
- IeeePartnerAbilities3Reg = 10;
- IeeeCopperSpecificControlReg = 16;
- IeeeSpecificStatusReg = 17;
- IeeeCopperSpecificStatusReg2 = 19;
- IeeeControlRegMac = 21;
- IeeePageAddressRegister = 22;
- (* Phy bits and masks *)
- Advertise10Half = 5;
- Advertise10Full = 6;
- Advertise100Half = 7;
- Advertise100Full = 8;
- Advertise100 = {Advertise100Full, Advertise100Half};
- Advertise10 = {Advertise10Full, Advertise10Half};
- Advertise1000 = {8, 9};
- IeeeCtrl1GbpsLinkspeed = 2040H;
- IeeeCtrlLinkSpeed = {6};
- IeeeCtrlLinkSpeed1000M = {6};
- IeeeCtrlLinkSpeed100M = {13};
- IeeeCtrlLinkSpeed10M = {};
- IeeeCtrlReset = {15};
- IeeeCtrlAutonegotiateEnable = {12};
- IeeeStatAutonegotiateCapable = {3};
- IeeeStatAutonegotiateComplete = {5};
- IeeeStatAutonegotiateRestart = {9};
- IeeeStat1gbpsExtensions = {8};
- IeeeAn1Ability = {5 .. 12};
- IeeeAn3Ability1Gbps = {10 .. 11};
- IeeeAn1Ability100Mbps = {7 .. 9};
- IeeeAn1Ability10Mbps = {5 .. 6};
- IeeeRgmiiTxRxClockDelayed = {4 .. 5};
- IeeeAsymmetricPause = {11};
- IeeePause = {10};
- IeeeAutonegError = {15};
- PhyDetectReg = 1;
- PhyDetect = {3, 11, 12};
- TYPE
- Buffer = ARRAY BufSize OF CHAR;
- (** Implements the Network.LinkDevice abstract class. *)
- LinkDevice * = OBJECT (Network.LinkDevice)
- VAR
- ctrl: Controller;
- PROCEDURE & Constr * (type, mtu, adrSize: LONGINT);
- VAR
- i: LONGINT;
- BEGIN
- Constr^(type, mtu, adrSize);
- FOR i := 0 TO LEN(broadcast) - 1 DO
- broadcast[i] := 0FFX
- END;
- END Constr;
- PROCEDURE Linked * (): LONGINT;
- BEGIN
- RETURN Network.LinkLinked
- 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 * (on: BOOLEAN);
- BEGIN
- Finalize^(on)
- END Finalize;
- END LinkDevice;
- (** Ethernet controller driver. *)
- Controller = OBJECT
- VAR
- (** Base of memory-mapped registers *)
- iobase: ADDRESS;
- dev: LinkDevice;
- phy: Phy;
- state, isStarted: LONGINT;
- speed: LONGINT;
- timer: Kernel.Timer;
- rxFrames: POINTER TO ARRAY OF Buffer;
- txFrame: Buffer;
- lastRxQBar, lastTxQBar: ADDRESS;
- rxBdBase, txBdBase: ADDRESS;
- options: SET;
- txBdStartAdr, txBdEndAdr, rxBdStartAdr, rxBdEndAdr: ADDRESS;
- kill, start: BOOLEAN;
- (* For DMA interaction *)
- buffer: POINTER TO ARRAY OF CHAR;
- (** Statistics *)
- nbrRxFrames, nbrtxFrames, nbrRxErrors, nbrTxErrors: LONGINT;
- (** Initializes the controller.
- iobase: base address of the registers
- *)
- PROCEDURE & Init * (iobase: ADDRESS; ld: LinkDevice);
- VAR
- i: LONGINT;
- reg: SET;
- (* TEST *)arp: ARRAY 28 OF CHAR;
- buf: ARRAY 256 OF Network.Buffer;
- BEGIN
- NEW(timer);
- NEW(rxFrames, RxBdCount);
- options := Defaults;
- SELF.iobase := iobase;
- dev := ld;
- dev.calcChecksum := {Network.ChecksumIP, Network.ChecksumTCP, Network.ChecksumUDP};
- kill := FALSE;
- start := FALSE;
- state := IsReady;
- Reset;
- (* Initialize HW *)
- IF Trace THEN KernelLog.String("Zynq.XEmac: Initializing hardware"); KernelLog.Ln END;
- SetMacAddress(1, SYSTEM.VAL(Network.LinkAdr, [0X, 0AX, 35X, 0X, 1X, 2X, 0X, 0X]));
- SetMdioDivisor(MdcDiv224);
- NEW(phy, iobase);
- speed := phy.linkSpeed;
- IF speed # 1000 THEN
- IF Trace THEN KernelLog.String("XEmac: error in speed initialization."); KernelLog.Ln END;
- RETURN
- END;
- SetOperatingSpeed(speed);
- SYSTEM.GET(iobase + Dmacr, reg);
- INCL(reg, 4);
- SYSTEM.PUT(iobase + Dmacr, reg);
- SetMdioDivisor(MdcDiv224);
- IF Trace THEN KernelLog.String("XEmac: Initializing DMA"); KernelLog.Ln END;
- FOR i := 0 TO 6000000 DO END;
- InitDMA;
-
- (* preallocate network stack buffers *)
- FOR i := 0 TO LEN(buf,0)-1 DO
- buf[i] := Network.GetNewBuffer();
- END;
- FOR i := 0 TO LEN(buf,0)-1 DO
- Network.ReturnBuffer(buf[i]);
- END;
- IF Trace THEN KernelLog.String("XEmac: Starting controller"); KernelLog.Ln END;
- Start
- END Init;
- (* Terminates the process *)
- PROCEDURE Kill;
- BEGIN {EXCLUSIVE}
- kill := TRUE
- END Kill;
- PROCEDURE Start;
- VAR
- reg: SET;
- BEGIN
- IF Trace THEN KernelLog.String("Starting XEmac"); KernelLog.Ln END;
- IF isStarted = IsStarted THEN RETURN END;
- (* Start DMA *)
- SYSTEM.PUT(iobase + Rxqbase, rxBdBase);
- SYSTEM.PUT(iobase + Txqbase, txBdBase);
- (* Clear any existing interrupt status *)
- SYSTEM.PUT(iobase + Isr, IxrAll);
- (* Optionally enable TX and RX *)
- IF TransmitterEnable IN options THEN
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg + NwctrlTxEn;
- SYSTEM.PUT(iobase + Nwctrl, reg)
- END;
- IF ReceiverEnable IN options THEN
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg + NwctrlRxEn;
- SYSTEM.PUT(iobase + Nwctrl, reg)
- END;
- (* Enable TX and RX interrupts *)
- SYSTEM.PUT(iobase + Ier, (IxrTxErr + IxrRxErr + {IxrTxCompl, IxrFrameRx}) * IxrAll);
- (*BEGIN {EXCLUSIVE}
- start := TRUE
- END;*)
- (*VAR
- reg: SET;
- BEGIN
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg + NwctrlStartTx;
- SYSTEM.PUT(iobase + Nwctrl, reg)*)
- END Start;
- PROCEDURE Stop;
- VAR
- reg: SET;
- BEGIN
- ASSERT(state = IsReady);
- (* Disable all interrupts *)
- SYSTEM.PUT32(iobase + Idr, IxrAll);
- (* Disable TX and RX *)
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg - (NwctrlRxEn + NwctrlTxEn);
- SYSTEM.PUT(iobase + Nwctrl, reg);
- isStarted := 0
- END Stop;
- PROCEDURE Transmit;
- VAR
- reg: SET;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac: transmitting"); KernelLog.Ln END;
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg + NwctrlStartTx;
- SYSTEM.PUT(iobase + Nwctrl, reg)
- END Transmit;
- (** Stop and restart device *)
- PROCEDURE Reset;
- VAR
- i, tmp: LONGINT;
- reg: SET;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac resetting controller"); KernelLog.Ln END;
- ASSERT(state = IsReady);
- Stop;
- options := Defaults;
- reg := (NwctrlStatclr + NwctrlMdEn) * (-NwctrlLoopEn);
- SYSTEM.PUT(iobase + Nwctrl, reg);
- reg := {};
- INCL(reg, Nwcfg100);
- INCL(reg, NwcfgFdEn);
- INCL(reg, NwcfgUcastHashEn);
- SYSTEM.PUT(iobase + Nwcfg, reg);
- i := RxBufSize DIV RxBufUnit;
- IF RxBufSize MOD RxBufUnit # 0 THEN INC(i) END;
- reg := SYSTEM.VAL(SET, LSH(i, DmacrRxBufShift)) * DmacrRxBuf + DmacrRxSize;
- INCL(reg, DmacrTxSize);
- SYSTEM.PUT(iobase + Dmacr, reg);
- SYSTEM.PUT32(iobase + Txsr, 0);
- SYSTEM.PUT32(iobase + Rxqbase, 0);
- SYSTEM.PUT32(iobase + Txqbase, 0);
- SYSTEM.PUT32(iobase + Rxsr, 0);
- SYSTEM.PUT32(iobase + Idr, IxrAll);
- SYSTEM.GET(iobase + Isr, reg);
- SYSTEM.PUT(iobase + Isr, reg);
- SYSTEM.PUT32(iobase + PhyMntnc, 0);
- ClearHash;
- (* Clear all MAC addresses *)
- FOR i := 1 TO 4 DO
- SetMacAddress(i, ZeroMAC);
- tmp := SetTypeIdCheck(i, 0)
- END;
- (* Clear all counters. *)
- FOR i := 0 TO (Last- OctTxL) DIV 4 - 1 DO
- SYSTEM.GET(iobase + OctTxL + 4 * i, reg)
- END;
- (* Disable receiver. *)
- SYSTEM.GET(iobase + Nwctrl, reg);
- SYSTEM.PUT(iobase + Nwctrl, reg - NwctrlRxEn);
- SetOptions(options - {TransmitterEnable, ReceiverEnable});
- ClearOptions(-options);
- END Reset;
- PROCEDURE ResetDevice;
- VAR
- options: SET;
- BEGIN
- Stop;
- options := SELF.options;
- Reset;
- SetOptions(options);
- ClearOptions(-options)
- END ResetDevice;
- PROCEDURE SendFrame (CONST dst: Network.LinkAdr; type: LONGINT; CONST l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
- VAR
- txLen, offset: LONGINT;
- bufferAdr, txbd: ADDRESS;
- intsEnabled: BOOLEAN;
- reg: SET;
- BEGIN (*{EXCLUSIVE}*)
- IF Trace THEN KernelLog.String("XEmac: Sending Frame"); KernelLog.Ln END;
- (* Prepare buffer *) (* This part is taken from RTL8169.Mod *)
- txLen := 14 + h3len + h4len + dlen;
- bufferAdr := ADDRESSOF(txFrame[0]);
- (* set destination mac address (first 6 bytes of eth frame) *)
- SYSTEM.MOVE(ADDRESSOF(dst[0]), bufferAdr, 6);
- (*txFrame[0] := dst[0]; txFrame[1] := dst[1]; txFrame[2] := dst[2]; txFrame[3] := dst[3]; txFrame[4] := dst[4]; txFrame[5] := dst[5];*)
- (* set source mac address (6 bytes @ offset 6 of eth frame) *)
- SYSTEM.MOVE(ADDRESSOF(dev.local[0]), bufferAdr + 6, 6);
- (*txFrame[6]:=000X;txFrame[7]:=00AX;txFrame[8]:=035X;txFrame[9]:=000X;txFrame[10]:=001X;txFrame[11]:=002X;*)
- (* set upper layer type, bring type from host to network byte order *)
- SYSTEM.PUT16(bufferAdr + 12, ROT(SYSTEM.VAL(INTEGER, SHORT(type)), 8));
- (*IF Trace THEN
- KernelLog.Buffer(txFrame, 0, txLen);
- KernelLog.Ln
- END;*)
- offset := 14;
- (* move layer 3 and layer 4 headers, data *)
- IF h3len > 0 THEN
- SYSTEM.MOVE(ADDRESSOF(l3hdr[0]), bufferAdr + offset, h3len);
- INC(offset, h3len);
- END;
- IF h4len > 0 THEN
- SYSTEM.MOVE(ADDRESSOF(l4hdr[0]), bufferAdr + offset, h4len);
- INC(offset, h4len);
- END;
- IF offset + dlen < BufSize THEN
- SYSTEM.MOVE(ADDRESSOF(data[0]) + dofs, bufferAdr + offset, dlen);
- INC(offset, dlen);
- END;
- (* make the frame at least 64 bytes long *)
- WHILE offset < 60 DO
- txFrame[offset] := CHR(0);
- INC(offset);
- INC(txLen)
- END;
- (*IF Trace THEN
- KernelLog.String("Sending frame of length ");
- KernelLog.Int(txLen, 0);
- KernelLog.Ln;
- KernelLog.Memory(bufferAdr, txLen)
- END;*)
- (* Send it with DMA *)
- intsEnabled := Machine.AreInterruptsEnabled();
- Machine.DisableInterrupts;
- SYSTEM.GET(iobase + Txqbase, txbd);
- IF txbd = 0 THEN txbd := txBdStartAdr END;
- Machine.FlushDCacheRange(ADDRESSOF(txFrame[0]), txLen);
- SYSTEM.PUT(txbd + BdAdrOffset, ADDRESSOF(txFrame));
- IF txbd # txBdEndAdr THEN
- SYSTEM.PUT(txbd + BdStatOffset, {TxBufLast} + SYSTEM.VAL(SET, txLen));
- ELSE
- IF Trace THEN KernelLog.String("END OF TXBUFFERS"); KernelLog.Ln END;
- SYSTEM.PUT(txbd + BdStatOffset, {TxBufLast, TxBufWrap} + SYSTEM.VAL(SET, txLen));
- END;
-
- (* no need to flush/invalidate cache for BD memory space
- Machine.FlushDCacheRange(txbd, BdSize);
- *)
-
- CODE
- DSB
- END;
- (* Transmit *)
- Transmit;
- IF intsEnabled THEN Machine.EnableInterrupts END;
- END SendFrame;
- (** Called by the polling body. Signals the new frames to the link device *)
- PROCEDURE ReceiveFrame;
- VAR
- currentBd, adr: ADDRESS;
- len, i: LONGINT;
- reg: SET;
- buf: Network.Buffer;
- type: INTEGER;
- BEGIN
- (*IF Trace THEN KernelLog.String("Receiving frame"); KernelLog.Ln END;*)
- currentBd := lastRxQBar;
- SYSTEM.GET(currentBd + BdAdrOffset, adr);
- adr := adr - (adr MOD 4);
- SYSTEM.GET(currentBd, reg);
- IF RxBufNew IN reg THEN
- (*IF Trace THEN
- KernelLog.String("Current BD: "); KernelLog.Address(currentBd); KernelLog.Ln;
- KernelLog.String("QBar: "); KernelLog.Address(SYSTEM.GET32(iobase + Rxqbase)); KernelLog.Ln
- END;*)
- IF SYSTEM.GET32(currentBd + 4) = 0 THEN
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg * SET(-NwctrlRxEn);
- SYSTEM.PUT(iobase + Nwctrl, reg);
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg + NwctrlRxEn + {18};
- SYSTEM.PUT(iobase + Nwctrl, reg)
- ELSE
- IF Trace THEN KernelLog.String("Receiving frame"); KernelLog.Ln END;
- SYSTEM.GET(currentBd + BdStatOffset, reg);
- len := SYSTEM.VAL(LONGINT, reg * RxBufLen);
- (* Invalidate DCache *)
- (* no need to flush/invalidate cache for BD memory space
- Machine.InvalidateDCacheRange(currentBd,BdSize);
- *)
- Machine.InvalidateDCacheRange(adr,len);
- (* Construct Frame *)
- buf := Network.GetNewBuffer(); ASSERT(buf # NIL);
- buf.ofs := 14;
- buf.len := len - 14;
- buf.next := NIL;
- buf.prev := NIL;
- buf.calcChecksum := dev.calcChecksum;
-
- SYSTEM.MOVE(adr+6,ADDRESSOF(buf.src[0]),6);
-
- type := INTEGER(SYSTEM.GET8(adr + 12)) * 100H + INTEGER(SYSTEM.GET8(adr + 13));
- SYSTEM.MOVE(adr,ADDRESSOF(buf.data[0]),len);
- dev.QueueBuffer(buf, type)
- END
- END;
- IF currentBd = rxBdEndAdr THEN
- SYSTEM.PUT32(currentBd + BdAdrOffset, adr + 2);
- lastRxQBar := rxBdStartAdr
- ELSE
- SYSTEM.PUT32(currentBd + BdAdrOffset, adr);
- INC(lastRxQBar, BdSize)
- END;
- SYSTEM.PUT32(currentBd + BdStatOffset, 0);
-
- (* no need to flush/invalidate cache for BD memory space
- Machine.FlushDCacheRange(currentBd, BdSize);
- *)
- END ReceiveFrame;
- PROCEDURE SetOptions (opts: SET);
- VAR
- reg, regNetCfg, regNewNetCfg: SET;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac.SetOptions: "); KernelLog.Hex(SYSTEM.VAL(ADDRESS, opts), -8); KernelLog.Ln END;
- ASSERT(state = IsReady);
- (* Many of these options will change the NET_CONFIG registers.
- * To reduce the amount of IO to the device, group these options here
- * and change them all at once.
- *)
- (* Grab current register contents *)
- SYSTEM.GET(iobase + Nwcfg, regNetCfg);
- regNewNetCfg := regNetCfg;
- IF Trace THEN KernelLog.String("regNetCfg="); KernelLog.Hex(SYSTEM.VAL(LONGINT, regNetCfg), -8); KernelLog.Ln END;
- (*
- * It is configured to max 1536.
- *)
- IF Frame1536 IN opts THEN
- regNewNetCfg := regNewNetCfg + {Nwcfg1536RxEn};
- END;
- (* Turn on VLAN packet only, only VLAN tagged will be accepted *)
- IF Vlan IN opts THEN
- regNewNetCfg := regNewNetCfg + {NwcfgNvlanDisc};
- END;
- (* Turn on FCS stripping on receive packets *)
- IF FcsStrip IN opts THEN
- regNewNetCfg := regNewNetCfg + {NwcfgFcsRem};
- END;
- (* Turn on length/type field checking on receive packets *)
- IF LenTypeErr IN opts THEN
- regNewNetCfg := regNewNetCfg + {NwcfgLengthErrDscrd};
- END;
- (* Turn on flow control *)
- IF FlowControl IN opts THEN
- regNewNetCfg := regNewNetCfg + {NwcfgPauseEn};
- END;
- (* Turn on promiscuous frame filtering (all frames are received) *)
- IF Promisc IN opts THEN
- regNewNetCfg := regNewNetCfg + {NwcfgCopyAllEn};
- END;
- (* Allow broadcast address reception *)
- IF Broadcast IN opts THEN
- regNewNetCfg := regNewNetCfg - {NwcfgBcastDi};
- END;
- (* Allow multicast address filtering *)
- IF Multicast IN opts THEN
- regNewNetCfg := regNewNetCfg + {NwcfgMcastHashEn};
- END;
- (* enable RX checksum offload *)
- IF RxChksumEnable IN opts THEN
- regNewNetCfg := regNewNetCfg + {NwcfgRxChkSumEn};
- END;
- (* Officially change the NET_CONFIG registers if it needs to be
- * modified.
- *)
- IF regNetCfg # regNewNetCfg THEN
- SYSTEM.PUT(iobase + Nwcfg, regNewNetCfg);
- END;
- IF Trace THEN KernelLog.String("regNewNetCfg="); KernelLog.Hex(SYSTEM.VAL(LONGINT, regNewNetCfg), -8); KernelLog.Ln END;
- (* Enable TX checksum offload *)
- IF TxChksumEnable IN opts THEN
- SYSTEM.GET(iobase + Dmacr, reg);
- reg := reg + {DmacrTcpChksum};
- SYSTEM.PUT(iobase + Dmacr, reg);
- IF Trace THEN KernelLog.String("DMACR_OFFSET reg="); KernelLog.Hex(SYSTEM.VAL(LONGINT, reg), -8); KernelLog.Ln END;
- END;
- (* Enable transmitter *)
- IF TransmitterEnable IN opts THEN
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg + NwctrlTxEn;
- SYSTEM.PUT(iobase + Nwctrl, reg);
- IF Trace THEN KernelLog.String("NWCTRL_OFFSET reg="); KernelLog.Hex(SYSTEM.VAL(LONGINT, reg), -8); KernelLog.Ln END;
- END;
- (* Enable receiver *)
- IF ReceiverEnable IN opts THEN
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg + NwctrlRxEn;
- SYSTEM.PUT(iobase + Nwctrl, reg);
- IF Trace THEN KernelLog.String("NWCTRL_OFFSET reg="); KernelLog.Hex(SYSTEM.VAL(LONGINT, reg), -8); KernelLog.Ln END;
- END;
- (* The remaining options not handled here are managed elsewhere in the
- * driver. No register modifications are needed at this time. Reflecting
- * the option in InstancePtr->Options is good enough for now.
- *)
- (* Set options word to its new value *)
- SELF.options := SELF.options + opts;
- IF Trace THEN KernelLog.String("SetOptions END "); KernelLog.Address(SYSTEM.VAL(ADDRESS, SELF.options)); KernelLog.Ln END;
- END SetOptions;
- PROCEDURE ClearOptions (opts: SET);
- VAR
- reg, old: SET;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac: Clear Options"); KernelLog.Ln END;
- SYSTEM.GET(iobase + Nwcfg, reg);
- old := reg;
- (*
- * It is configured to max 1536.
- *)
- IF Frame1536 IN opts THEN
- EXCL(reg, Nwcfg1536RxEn);
- END;
- (* Turn off VLAN packet only, only VLAN tagged will be accepted *)
- IF Vlan IN opts THEN
- EXCL(reg, NwcfgNvlanDisc);
- END;
- (* Turn off FCS stripping on receive packets *)
- IF FcsStrip IN opts THEN
- EXCL(reg, NwcfgFcsRem);
- END;
- (* Turn off length/type field checking on receive packets *)
- IF LenTypeErr IN opts THEN
- EXCL(reg, NwcfgLengthErrDscrd);
- END;
- (* Turn off flow control *)
- IF FlowControl IN opts THEN
- EXCL(reg, NwcfgPauseEn);
- END;
- (* Turn off promiscuous frame filtering (all frames are received) *)
- IF Promisc IN opts THEN
- EXCL(reg, NwcfgCopyAllEn);
- END;
- (* Forbid broadcast address reception *)
- IF Broadcast IN opts THEN
- EXCL(reg, NwcfgBcastDi);
- END;
- (* Forbid multicast address filtering *)
- IF Multicast IN opts THEN
- EXCL(reg, NwcfgMcastHashEn);
- END;
- (* Disable RX checksum offload *)
- IF RxChksumEnable IN opts THEN
- EXCL(reg, NwcfgRxChkSumEn);
- END;
- (* Officially change the NET_CONFIG registers if it needs to be
- * modified.
- *)
- IF reg # old THEN
- SYSTEM.PUT(iobase + Nwcfg, reg);
- END;
- IF Trace THEN KernelLog.String("regNewNetCfg="); KernelLog.Hex(SYSTEM.VAL(LONGINT, reg), -8); KernelLog.Ln END;
- (* Disable TX checksum offload *)
- IF TxChksumEnable IN opts THEN
- SYSTEM.GET(iobase + Dmacr, reg);
- EXCL(reg, DmacrTcpChksum);
- SYSTEM.PUT(iobase + Dmacr, reg);
- IF Trace THEN KernelLog.String("DMACR_OFFSET reg="); KernelLog.Hex(SYSTEM.VAL(LONGINT, reg), -8); KernelLog.Ln END;
- END;
- (* Disable transmitter *)
- IF TransmitterEnable IN opts THEN
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg * SET(-NwctrlTxEn);
- SYSTEM.PUT(iobase + Nwctrl, reg);
- IF Trace THEN KernelLog.String("NWCTRL_OFFSET reg="); KernelLog.Hex(SYSTEM.VAL(LONGINT, reg), -8); KernelLog.Ln END;
- END;
- (* Disable receiver *)
- IF ReceiverEnable IN opts THEN
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg * SET(-NwctrlRxEn);
- SYSTEM.PUT(iobase + Nwctrl, reg);
- IF Trace THEN KernelLog.String("NWCTRL_OFFSET reg="); KernelLog.Hex(SYSTEM.VAL(LONGINT, reg), -8); KernelLog.Ln END;
- END;
- SELF.options := SELF.options * (-opts);
- END ClearOptions;
- PROCEDURE ClearHash;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac: Clear Hash"); KernelLog.Ln END;
- ASSERT(state = IsReady);
- SYSTEM.PUT32(iobase + HashL, 0);
- SYSTEM.PUT32(iobase + HashH, 0)
- END ClearHash;
- PROCEDURE SetMdioDivisor (divisor: LONGINT);
- VAR
- reg: SET;
- BEGIN
- ASSERT(state = IsReady);
- (* Only last 3 bits are valid *)
- ASSERT(divisor < 8);
- SYSTEM.GET(iobase + Nwcfg, reg);
- reg := reg * SET(-NwcfgMdcClkDiv);
- reg := reg + SYSTEM.VAL(SET, LSH(divisor, NwcfgMdcShift));
- SYSTEM.PUT(iobase + Nwcfg, reg);
- END SetMdioDivisor;
- PROCEDURE SetOperatingSpeed (speed: LONGINT);
- VAR
- reg: SET;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac: setting operating speed."); KernelLog.Ln END;
- ASSERT(state = IsReady);
- ASSERT((speed = 10) OR (speed = 100) OR (speed = 1000));
- SYSTEM.GET(iobase + Nwcfg, reg);
- reg := reg - {Nwcfg1000, Nwcfg100};
- CASE speed OF
- 10:
- |100:
- INCL(reg, Nwcfg100)
- |1000:
- INCL(reg, Nwcfg1000)
- END;
- SYSTEM.PUT(iobase + Nwcfg, reg);
- IF Trace THEN KernelLog.String("Waiting for operation speed to stabilize"); KernelLog.Ln END;
- timer.Sleep(1000);
- IF Trace THEN KernelLog.String("XEmac: operating speed set."); KernelLog.Ln END;
- END SetOperatingSpeed;
- (*! TODO: change parameter interface to a more convenient one *)
- PROCEDURE SetMacAddress(index: LONGINT; mac: Network.LinkAdr);
- VAR
- reg: SET;
- BEGIN
- ASSERT(index > 0);
- DEC(index);
- reg := SYSTEM.VAL(SET, ORD(mac[0]) + LSH(ORD(mac[1]), 8) + LSH(ORD(mac[2]), 16) + LSH(ORD(mac[3]), 24));
- SYSTEM.PUT(iobase + Laddr1l + (index * 8), reg);
- (* There are reserved bits in TOP so don't affect them *)
- SYSTEM.GET(iobase + Laddr1h + (index * 8), reg);
- reg := reg * SET(-LaddrMach) + SYSTEM.VAL(SET, ORD(mac[4]) + LSH(ORD(mac[5]), 8));
- SYSTEM.PUT(iobase + Laddr1h + index * 8, reg);
- dev.local := mac;
- IF Trace THEN
- KernelLog.String("XEmac MAC address set to: ");
- KernelLog.Hex(ORD(mac[0]), -2); KernelLog.String(".");
- KernelLog.Hex(ORD(mac[1]), -2); KernelLog.String(".");
- KernelLog.Hex(ORD(mac[2]), -2); KernelLog.String(".");
- KernelLog.Hex(ORD(mac[3]), -2); KernelLog.String(".");
- KernelLog.Hex(ORD(mac[4]), -2); KernelLog.String(".");
- KernelLog.Hex(ORD(mac[5]), -2); KernelLog.Ln
- END
- END SetMacAddress;
- PROCEDURE SetTypeIdCheck(index, idCheck: LONGINT): LONGINT;
- BEGIN
- ASSERT(state = IsReady);
- ASSERT((index > 0) & (index <= MaxTypeId));
- IF isStarted = IsStarted THEN
- RETURN IsStarted
- END;
- SYSTEM.PUT(iobase + Match1 + index * 4, idCheck);
- RETURN Success
- END SetTypeIdCheck;
- PROCEDURE InitDMA;
- CONST
- MB = 1024*1024;
- VAR
- beginAdr, endAdr, adr: ADDRESS;
- reg: SET;
- i: LONGINT;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac: Starting DMA"); KernelLog.Ln END;
-
- (*
- NEW(buffer, (RxBdCount + TxBdCount + 20) * BdSize);
- *)
- (* allocate 2 pages (each page is 1 MBytes) of memory in Heaps for mapping one full page uncached
- without affecting any adjacent data *)
- NEW(buffer,2*MB);
- ASSERT((RxBdCount + TxBdCount + 20) * BdSize <= MB);
- beginAdr := ADDRESSOF(buffer[0]);
- beginAdr := beginAdr + (MB - beginAdr MOD MB);
- ASSERT(beginAdr MOD MB = 0);
- Machine.DisableDCacheRange(beginAdr,MB);
-
- (* setup DMA RX buffer descriptors *)
- rxBdStartAdr := beginAdr;
- endAdr := beginAdr + (RxBdCount - 1) * BdSize;
- rxBdEndAdr := endAdr;
- i := 0;
- adr := beginAdr;
- WHILE adr < endAdr DO
- SYSTEM.PUT32(adr + BdAdrOffset, ADDRESSOF(rxFrames[i][0]));
- INC(adr, BdSize);
- INC(i)
- END;
- SYSTEM.PUT32(adr + BdAdrOffset, ADDRESSOF(rxFrames[i][0]) + 2);
- lastRxQBar := beginAdr;
- rxBdBase := beginAdr;
- CODE
- DSB
- END;
-
- (* no need to flush/invalidate cache for BD memory space
- (* Flush DCache *)
- Machine.FlushDCacheRange(beginAdr, RxBdCount * BdSize);
- *)
-
- IF Trace THEN KernelLog.String("XEmac: RX buffers are set up."); KernelLog.Ln END;
- (* setup DMA TX buffer descriptors *)
- beginAdr := endAdr + BdSize;
- txBdStartAdr := beginAdr;
- endAdr := beginAdr + (TxBdCount - 1) * BdSize;
- txBdEndAdr := endAdr;
- adr := beginAdr;
- WHILE adr < endAdr DO
- SYSTEM.PUT32(adr, 0);
- SYSTEM.PUT32(adr + 4, {TxBufUsed});
- INC(adr, BdSize)
- END;
- SYSTEM.PUT32(adr + 4, {TxBufUsed, TxBufWrap});
- lastTxQBar := beginAdr;
- txBdBase := beginAdr;
- CODE
- DSB
- END;
-
- (* no need to flush/invalidate cache for BD memory space
- (* Flush DCache *)
- Machine.FlushDCacheRange(txBdBase, TxBdCount * BdSize);
- *)
-
- IF Trace THEN KernelLog.String("XEmac: TX buffers are set up."); KernelLog.Ln END;
- Objects.InstallHandler(SELF.InterruptHandler, IRQ);
- IF Trace THEN KernelLog.String("DMA Initialized"); KernelLog.Ln END
- END InitDMA;
- (**
- Interrupt handler -- tries to handle the maximum number of IRQs
- at once.
- *)
- PROCEDURE InterruptHandler;
- VAR
- regISR, regSR: SET;
- BEGIN
- ASSERT(state = IsReady);
- (* Get and clear interrupts *)
- SYSTEM.GET(iobase + Isr, regISR);
- SYSTEM.PUT(iobase + Isr, regISR);
- (* Transmit complete interrupt *)
- IF IxrTxCompl IN regISR THEN
- SYSTEM.PUT(iobase + Txsr, {TxsrTxCompl, TxsrUsedRead});
- SendHandler
- END;
- (* Receive complete interrupt *)
- IF IxrFrameRx IN regISR THEN
- SYSTEM.PUT(iobase + Rxsr, {RxsrFrameRx, RxsrBuffna});
- ReceiveHandler
- END;
- (* Receive error conditions interrupt *)
- IF IxrRxErr * regISR # {} THEN
- (* Clear Rx status register *)
- SYSTEM.GET(iobase + Rxsr, regSR);
- SYSTEM.PUT(iobase + Rxsr, regSR);
- IF IxrRxUsed IN regISR THEN
- (* Flush a packet from Rx SRAM *)
- SYSTEM.GET(iobase + Nwctrl, regSR);
- SYSTEM.PUT(iobase + Nwctrl, regSR + {18})
- END;
- ErrorHandler(Recv, regSR)
- END;
- (* Transmit error interrupt
- TxCompl also activates TxUsed when asserted: we have to check for a real error.
- *)
- IF (IxrTxErr * regISR # {}) & (~(IxrTxCompl IN regISR)) THEN
- SYSTEM.GET(iobase + Txsr, regSR);
- SYSTEM.PUT(iobase + Txsr, regSR);
- ErrorHandler(Send, regSR)
- END;
- END InterruptHandler;
- PROCEDURE SendHandler;
- VAR
- reg: SET;
- currBdPtr: ADDRESS;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac.SendHandler"); KernelLog.Ln END;
- SYSTEM.GET(iobase + Txsr, reg);
- SYSTEM.PUT(iobase + Txsr, reg);
- LOOP
- currBdPtr := lastTxQBar;
- IF currBdPtr = SYSTEM.GET32(iobase + Txqbase) THEN EXIT END;
- SYSTEM.PUT32(currBdPtr + BdAdrOffset, 0);
- IF currBdPtr = txBdEndAdr THEN
- SYSTEM.PUT(currBdPtr + BdStatOffset, {TxBufUsed, TxBufWrap});
- lastTxQBar := txBdStartAdr
- ELSE
- SYSTEM.PUT(currBdPtr + BdStatOffset, {TxBufUsed});
- INC(lastTxQBar, BdSize)
- END
- END;
- IF Trace THEN KernelLog.String("XEmac.SendHandler END"); KernelLog.Ln END
- END SendHandler;
- PROCEDURE ReceiveHandler;
- (*VAR
- buf: Network.Buffer;
- type: LONGINT;*)
- VAR
- reg: SET;
- tmp: LONGINT;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac.ReceiveHandler"); KernelLog.Ln END;
- SYSTEM.GET(iobase + Rxsr, reg);
- SYSTEM.PUT(iobase + Rxsr, reg);
- SYSTEM.GET(iobase + Rxcnt, tmp);
- IF tmp = 0 THEN
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg * SET(-NwctrlRxEn);
- SYSTEM.PUT(iobase + Nwctrl, reg);
- SYSTEM.GET(iobase + Nwctrl, reg);
- reg := reg + NwctrlRxEn;
- SYSTEM.PUT(iobase + Nwctrl, reg)
- END
- END ReceiveHandler;
- PROCEDURE ErrorHandler (direction: CHAR; errorWord: SET);
- BEGIN
- IF Trace THEN KernelLog.String("XEmac.ErrorHandler: Error while ") END;
- CASE direction OF
- Send:
- KernelLog.String("sending"); KernelLog.Ln;
- IF TxsrHrespnok IN errorWord THEN
- KernelLog.String("[XEmac ERROR] Transmit DMA error"); KernelLog.Ln
- END;
- IF TxsrUrun IN errorWord THEN
- KernelLog.String("[XEmac ERROR] Transmit underrun"); KernelLog.Ln
- END;
- IF TxsrBufExh IN errorWord THEN
- KernelLog.String("[XEmac ERROR] Transmit buffer exhausted"); KernelLog.Ln
- END;
- IF TxsrRxOvr IN errorWord THEN
- KernelLog.String("[XEmac ERROR] Transmit retry limit exceeded"); KernelLog.Ln
- END;
- IF TxsrFrameRx IN errorWord THEN
- KernelLog.String("[XEmac ERROR] Transmit collision"); KernelLog.Ln
- END;
- IF TxsrUsedRead IN errorWord THEN
- KernelLog.String("[XEmac ERROR] Transmit buffer not available"); KernelLog.Ln;
- KernelLog.String("QBar = "); KernelLog.Address(SYSTEM.GET32(iobase + Txqbase)); KernelLog.Ln
- END;
- |Recv:
- KernelLog.String("receiving"); KernelLog.Ln;
- IF RxsrHrespnok IN errorWord THEN
- KernelLog.String("[XEmac ERROR] Receive DMA error"); KernelLog.Ln
- END;
- IF RxsrRxOvr IN errorWord THEN
- KernelLog.String("[XEmac ERROR] Receive overrun"); KernelLog.Ln
- END;
- IF RxsrBuffna IN errorWord THEN
- KernelLog.String("[XEmac ERROR] Receive buffer not available"); KernelLog.Ln
- END
- END;
- ResetDevice
- END ErrorHandler;
- PROCEDURE SendTestFrame;
- VAR
- txbd: ADDRESS;
- intsEnabled: BOOLEAN;
- BEGIN
- txFrame[0]:=0FFX;txFrame[1]:=0FFX;txFrame[2]:=0FFX;txFrame[3]:=0FFX;txFrame[4]:=0FFX;txFrame[5]:=0FFX;
- txFrame[6]:=000X;txFrame[7]:=00AX;txFrame[8]:=035X;txFrame[9]:=000X;txFrame[10]:=001X;txFrame[11]:=002X;
- txFrame[12]:=008X;txFrame[13]:=006X;txFrame[14]:=000X;txFrame[15]:=001X;
- txFrame[16]:=008X;txFrame[17]:=000X;txFrame[18]:=006X;txFrame[19]:=004X;txFrame[20]:=000X;txFrame[21]:=001X;txFrame[22]:=000X;txFrame[23]:=00AX;
- txFrame[24]:=035X;txFrame[25]:=000X;txFrame[26]:=001X;txFrame[27]:=002X;txFrame[28]:=0C0X;txFrame[29]:=0A8X;txFrame[30]:=001X;txFrame[31]:=00AX;
- txFrame[32]:=000X;txFrame[33]:=000X;txFrame[34]:=000X;txFrame[35]:=000X;txFrame[36]:=000X;txFrame[37]:=000X;txFrame[38]:=0C0X;txFrame[39]:=0A8X;
- txFrame[40]:=001X;txFrame[41]:=00AX;txFrame[42]:=000X;txFrame[43]:=000X;txFrame[44]:=000X;txFrame[45]:=000X;txFrame[46]:=000X;txFrame[47]:=000X;
- txFrame[48]:=001X;txFrame[49]:=00AX;txFrame[50]:=000X;txFrame[51]:=000X;txFrame[52]:=000X;txFrame[53]:=000X;txFrame[54]:=000X;txFrame[55]:=000X;
- txFrame[56]:=001X;txFrame[57]:=00AX;txFrame[58]:=000X;txFrame[59]:=000X;
- KernelLog.String("Sending Test Frame"); KernelLog.Ln;
- KernelLog.Address(ADDRESSOF(txFrame)); KernelLog.Ln;
- KernelLog.Buffer(txFrame, 0, 60);
- (* Send it with DMA *)
- intsEnabled := Machine.AreInterruptsEnabled();
- Machine.DisableInterrupts;
- SYSTEM.GET(iobase + Txqbase, txbd);
- KernelLog.String("SendTestFrame: txbd = "); KernelLog.Address(txbd); KernelLog.Ln;
- IF txbd = 0 THEN txbd := txBdStartAdr END;
- KernelLog.String("SendTestFrame: txbd = "); KernelLog.Address(txbd); KernelLog.Ln;
- Machine.FlushDCacheRange(ADDRESSOF(txFrame), 60);
- SYSTEM.PUT(txbd + BdAdrOffset, ADDRESSOF(txFrame));
- IF txbd # txBdEndAdr THEN
- SYSTEM.PUT(txbd + BdStatOffset, {TxBufLast} + SYSTEM.VAL(SET, 60));
- ELSE
- SYSTEM.PUT(txbd + BdStatOffset, {TxBufLast, TxBufWrap} + SYSTEM.VAL(SET, 60));
- END;
-
- (* no need to flush/invalidate cache for BD memory space
- Machine.FlushDCacheRange(txbd, BdSize);
- *)
-
- CODE
- DSB
- END;
- (* Transmit *)
- Transmit;
- IF intsEnabled THEN Machine.EnableInterrupts END;
- IF Trace THEN KernelLog.String("Frame sent"); KernelLog.Ln END
- END SendTestFrame;
- PROCEDURE DumpDBMem(start: ADDRESS; count: LONGINT);
- VAR
- i: LONGINT;
- BEGIN
- FOR i := 0 TO count DO
- KernelLog.Address(start); KernelLog.String(": ");
- KernelLog.Address(SYSTEM.GET32(start)); KernelLog.String(" - ");
- INC(start, 4);
- KernelLog.Address(SYSTEM.GET32(start)); KernelLog.Ln;
- INC(start, 4)
- END;
- END DumpDBMem;
- BEGIN {ACTIVE}
- (* Receive is done by polling *)
- (*BEGIN {EXCLUSIVE}
- AWAIT(start)
- END;*)
- LOOP
- (*BEGIN {EXCLUSIVE}
- IF kill THEN EXIT END
- END;*)
- IF lastRxQBar # SYSTEM.GET32(iobase + Rxqbase) THEN
- ReceiveFrame
- END
- END
- END Controller;
- (** Phy subsystem of the controller. *)
- Phy = OBJECT
- VAR
- iobase, phybase: ADDRESS;
- linkSpeed: LONGINT;
- timer: Kernel.Timer;
- PROCEDURE & Setup * (iobase: ADDRESS);
- BEGIN
- SELF.iobase := iobase;
- NEW(timer);
- IF LinkSpeedMode = LinkSpeedAutodetect THEN
- linkSpeed := GetIEEEPhySpeed();
- IF linkSpeed = 1000 THEN
- IF Trace THEN KernelLog.String("Autonegociated speed: 1000 MB/s"); KernelLog.Ln END;
- SetUpSLCRDivisors(1000)
- ELSIF linkSpeed = 100 THEN
- IF Trace THEN KernelLog.String("Autonegociated speed: 100 MB/s"); KernelLog.Ln END;
- SetUpSLCRDivisors(100)
- ELSIF linkSpeed = 10 THEN
- IF Trace THEN KernelLog.String("Autonegociated speed: 10 MB/s"); KernelLog.Ln END;
- SetUpSLCRDivisors(10)
- ELSE
- IF Trace THEN KernelLog.String("Defaulting autonegociated speed to 10 MB/s"); KernelLog.Ln END;
- SetUpSLCRDivisors(10)
- END;
- RETURN
- ELSIF LinkSpeedMode = LinkSpeed1000 THEN
- linkSpeed := 1000;
- ELSIF LinkSpeedMode = LinkSpeed100 THEN
- linkSpeed := 100;
- ELSE
- linkSpeed := 10;
- END;
- SetUpSLCRDivisors(linkSpeed);
- ConfigureIEEEPhySpeed(linkSpeed);
- timer.Sleep(1000)
- END Setup;
- PROCEDURE Detect (): ADDRESS;
- VAR
- status, phyReg: LONGINT;
- phyAdr: ADDRESS;
- BEGIN
- IF Trace THEN KernelLog.String("XEmac: Detecting PHY"); KernelLog.Ln END;
- phyAdr := 31;
- WHILE phyAdr > 0 DO
- status := Read(phyAdr, PhyDetectReg, phyReg);
- IF (phyReg # 0FFFFH) & (SYSTEM.VAL(SET, phyReg) * PhyDetect = PhyDetect) THEN
- IF Trace THEN KernelLog.String("Found PHY at "); KernelLog.Address(phyAdr); KernelLog.Ln END;
- RETURN phyAdr
- END;
- DEC(phyAdr)
- END;
- IF Trace THEN KernelLog.String("PHY not found. Assuming its address is 0"); KernelLog.Ln END;
- RETURN 0
- END Detect;
- PROCEDURE GetIEEEPhySpeed (): LONGINT;
- VAR
- temp, control, res, status, capabilities: LONGINT;
- phyAdr: ADDRESS;
- BEGIN
- phyAdr := Detect();
- IF Trace THEN KernelLog.String("Start PHY autonegociation"); KernelLog.Ln END;
- res := Write(phyAdr, IeeePageAddressRegister, 2);
- res := Read(phyAdr, IeeeControlRegMac, control);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeRgmiiTxRxClockDelayed);
- res := Write(phyAdr, IeeeControlRegMac, control);
- res := Write(phyAdr, IeeePageAddressRegister, 0);
- res := Read(phyAdr, IeeeAutonegoAdvertiseReg, control);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeAsymmetricPause + IeeePause + Advertise100 + Advertise10);
- res := Write(phyAdr, IeeeAutonegoAdvertiseReg, control);
- res := Read(phyAdr, Ieee1000AdvertiseReg, control);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + Advertise1000);
- res := Write(phyAdr, Ieee1000AdvertiseReg, control);
- res := Write(phyAdr, IeeePageAddressRegister, 0);
- res := Read(phyAdr, IeeeCopperSpecificControlReg, control);
- control := control + LSH(7, 12); (* Max number of gigabit attemps *)
- INCL(SYSTEM.VAL(SET, control), 11); (* Enable dowshift *)
- res := Write(phyAdr, IeeeCopperSpecificControlReg, control);
- res := Read(phyAdr, IeeeControlReg, control);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeCtrlAutonegotiateEnable);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeStatAutonegotiateRestart);
- res := Write(phyAdr, IeeeControlReg, control);
- res := Read(phyAdr, IeeeControlReg, control);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeCtrlReset);
- res := Write(phyAdr, IeeeControlReg, control);
- REPEAT
- IF Trace THEN KernelLog.String("Waiting for PHY reset"); KernelLog.Ln END;
- res := Read(phyAdr, IeeeControlReg, control)
- UNTIL SYSTEM.VAL(SET, control) * IeeeCtrlReset = {};
- IF Trace THEN KernelLog.String("Waiting for PHY to complete autonegotiation"); KernelLog.Ln END;
- res := Read(phyAdr, IeeeStatusReg, status);
- WHILE SYSTEM.VAL(SET, status) * IeeeStatAutonegotiateComplete = {} DO
- timer.Sleep(1000);
- res := Read(phyAdr, IeeeCopperSpecificStatusReg2, temp);
- IF Trace & (SYSTEM.VAL(SET, temp) * IeeeAutonegError # {}) THEN
- KernelLog.String("Autonegotiation error");
- KernelLog.Ln
- END;
- res := Read(phyAdr, IeeeStatusReg, status)
- END;
- IF Trace THEN KernelLog.String("Autonegotiation complete"); KernelLog.Ln END;
- res := Read(phyAdr, IeeeSpecificStatusReg, capabilities);
- IF 15 IN SYSTEM.VAL(SET, capabilities) THEN
- RETURN 1000 (* MB/s *)
- ELSIF 14 IN SYSTEM.VAL(SET, capabilities) THEN
- RETURN 100 (* MB/s *)
- ELSE
- RETURN 10 (* MB/s *)
- END
- END GetIEEEPhySpeed;
- PROCEDURE ConfigureIEEEPhySpeed (speed: LONGINT);
- VAR
- control, res, wait: LONGINT;
- phyAdr: ADDRESS;
- BEGIN
- phyAdr := Detect();
- res := Write(phyAdr, IeeePageAddressRegister, 2);
- res := Read(phyAdr, IeeeControlRegMac, control);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeRgmiiTxRxClockDelayed);
- res := Write(phyAdr, IeeeControlRegMac, control);
- res := Write(phyAdr, IeeePageAddressRegister, 0);
- res := Read(phyAdr, IeeeAutonegoAdvertiseReg, control);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeAsymmetricPause);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeePause);
- res := Write(phyAdr, IeeeAutonegoAdvertiseReg, control);
- res := Read(phyAdr, IeeeControlReg, control);
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) * (-IeeeCtrlLinkSpeed1000M) * (-IeeeCtrlLinkSpeed100M) * (-IeeeCtrlLinkSpeed10M));
- IF linkSpeed = 1000 THEN
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeCtrlLinkSpeed1000M)
- ELSIF linkSpeed = 100 THEN
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeCtrlLinkSpeed100M)
- (* Don't advertise PHY speed of 1000 MBPS *)
- ELSIF linkSpeed = 10 THEN
- control := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, control) + IeeeCtrlLinkSpeed10M)
- END;
- END ConfigureIEEEPhySpeed;
- PROCEDURE SetUpSLCRDivisors (div: LONGINT);
- END SetUpSLCRDivisors;
- PROCEDURE Write (address, register: ADDRESS; data: LONGINT): LONGINT;
- VAR
- reg, mgtcr, ipisr: SET;
- BEGIN
- IF Trace THEN KernelLog.String("PHY write"); KernelLog.Ln END;
- SYSTEM.GET(iobase + Nwsr, reg);
- (* Make sure no other PHY operation is currently in progress *)
- IF ~(NwsrMdioIdle IN reg) THEN
- IF Trace THEN KernelLog.String("XEmac Phy write aborted: PHY busy"); KernelLog.Ln END;
- RETURN EmacMiiBusy
- END;
- (* Construct Mgtcr mask for the operation *)
- mgtcr := PhyMntncOp + PhyMntncOpW + SYSTEM.VAL(SET, LSH(phybase, PhyMntncPhyAdShift))
- + SYSTEM.VAL(SET, LSH(address, PhyMntncPhyAdShift))
- + SYSTEM.VAL(SET, LSH(register, PhyMntncPhRegShift)) + SYSTEM.VAL(SET,data);
- SYSTEM.PUT(iobase + PhyMntnc, mgtcr);
- REPEAT
- SYSTEM.GET(iobase + Nwsr, ipisr)
- UNTIL NwsrMdioIdle IN ipisr;
- RETURN Success
- END Write;
- PROCEDURE Read (address, register: ADDRESS; VAR data: LONGINT): LONGINT;
- VAR
- reg, ipisr, mgtcr: SET;
- BEGIN
- SYSTEM.GET(iobase + Nwsr, reg);
- IF ~(NwsrMdioIdle IN reg) THEN
- IF Trace THEN KernelLog.String("XEmac Phy read aborted: PHY busy"); KernelLog.Ln END;
- RETURN EmacMiiBusy
- END;
- mgtcr := PhyMntncOp + PhyMntncOpR
- + SYSTEM.VAL(SET, LSH(address, PhyMntncPhyAdShift))
- + SYSTEM.VAL(SET, LSH(register, PhyMntncPhRegShift));
- SYSTEM.PUT(iobase + PhyMntnc, mgtcr);
- REPEAT
- SYSTEM.GET(iobase + Nwsr, ipisr)
- UNTIL NwsrMdioIdle IN ipisr;
- data := SYSTEM.GET32(iobase + PhyMntnc) MOD 10000H;
- RETURN Success
- END Read;
- END Phy;
- VAR
- ld: LinkDevice;
- res: LONGINT;
- BEGIN
- NEW(ld, Network.TypeEthernet, 1500, 6); (*! What is the correct MTU? *)
- ld.SetName("XEmac");
- Network.registry.Add(ld, res);
- NEW(ld.ctrl, ADDRESS(0E000B000H), ld);
- END XEmac.
|