; ; File: Mace.a ; ; Contains: Routines to support MACE when coupled with a PSC-style DMA model. ; ; Written by: Mark A. Law ,3-March-92 ; ; Copyright: й 1992-1993 by Apple Computer, Inc. All rights reserved. ; ; This file is used in these builds: Mac32 ; ; Change History (most recent first): ; ; 7/26/93 mal Fixed bug where drvr can fail to open if VM on and logical to ; physical address mapping of recv buffers are not 1 to 1. See ; GetPkt(). ; 6/14/93 kc Roll in Ludwig. ; 5/14/93 mal #1084946 Fixed race between xmit interrupt and non-interrupt ; rtns. that could result in sending out-of-order packets. ; 5/3/93 mal #1082628 Fixed race between deferred task and int. hndlr. rtns. ; See MaceRecv:@exit for details. ; 5/1/93 mal #1082434 Changed calling sequence to GetMem/FreeMem (see ; MaceEnet.a). Removed PSC debugging code, we support ONLY most ; current PSC, │ upgraded EVT5. ; 3/21/93 mal Fix last checkin bug in WriteLAF where MACE_MAC_CONFIG must be ; saved. ; 3/21/93 mal Remove Curio A2 support, ie. evt3 support. Removed use of ; _SetIntMask. Write-once on bug-fixed PSC. ; 3/16/93 chp Replace references to the obsolete PSCIntTbl lomem with ; references to the equivalent field in ExpandMem. ; 2/17/93 mal Moved receive chain/buffer headers out of unused portion of DMA ; buffer and into separate memory block. ; 1/27/93 mal Added MACEecfg rsrc support. Changed promiscuous mode support to ; lower main codepath risk. ; 12/4/92 mal Turned off debug code; promiscuous change to MaceRecv(); no ; longer deliver pkts with overflow error; added RCVCO counter; ; improved error handling if TranslateAddress fails. ; 11/19/92 mal Added PSC-bug recv DMA chnl checks; made ResetMace more robust; ; chg'd alignment method on recv buffers; added rcv collision cnt; ; chg'd MaceHalt to dequeue DT ; 11/10/92 mal Fixed bug in Mace open that could corrupt memory byte off A3; ; Corrected reporting of Recv FIFO overflow to ; InternalMacRecvError. ; 10/30/92 mal Fixed race cond. between deferred task & int. hndlr to give ; better recv perf.; added cmd/stat reg debug cuz of psc hw bug; ; disable all ints at end of ResetMace; call FreeMemory if error ; in MaceInit; misc global cleanup; misc comment cleanup. ; 10/26/92 mal Updated to ESD's latest stats equs. ; 10/26/92 mal Fixed some bugs and modified recv/xmit buffer memory allocation ; loop in open(). ; 10/13/92 mal -perf. improvement: removed all memory indirect preindexed ea's; ; -changed status to lw and always deliver to RecvRtn; -added temp ; code to handle PSC addr/cnt bug on 33 Mhz evt4. ; <1> 10/6/92 GDW New location for ROMLink tool. ; 9/14/92 mal -Updated SNMP counters; -added temp code to handle all Curio ; revs up to B0 ; 7/27/92 mal Added temp code to handle version 1 'ebfr's. ; 7/25/92 mal Added support for HW's maximum receive buffer configuration. ; Fixed xmit path bug where pkts could be sent out of order ; (stress). Fixed recv path bug to ensure correct reg set primed ; when only 1 chain available (heavy stress). Added recv/xmit ; bus error handlers. Improved MACEHALT routine. ; 6/26/92 mal Expanded # of maceinit parms saved in globals. ; 6/22/92 mal New drvr to support PSC2's (EVT2) Ethernet DMA receive model. ; 5/21/92 RB Removed the inclusion of VMCalls.a, got rid of a warning ; branch to next instruction and included InternalOnlyEqu.a ; 5/5/92 mal Removed some unused global vars ; 4/30/92 mal Expanded interface between MaceEnet.a and Mace.a. ; ; To Do: ; ; Notes: Initial version provides support for Cyclone builtin Ethernet. ; ; PRINT OFF INCLUDE 'SysEqu.a' ; System definitions INCLUDE 'SysErr.a' ; System errors INCLUDE 'Traps.a' ; Traps definitions INCLUDE 'GestaltEqu.a' INCLUDE 'InternalOnlyEqu.a' ; lowmem globals INCLUDE 'HardwarePrivateEqu.a' INCLUDE 'UniversalEqu.a' ; lowmem global records INCLUDE 'ATalkMacros.a' ; Nifty Macros INCLUDE 'SysPrivateEqu.a' ; ExpandMem defs ; Conditional compile equates COUNTERS EQU 0 BUFDEBUG EQU 0 DEBUG EQU 0 SETDEBUG EQU 0 SETDEBUGFAIL EQU 0 SETCSDEBUG EQU 0 SETCSDEBUGFAIL EQU 0 USEDEFERREDTASK EQU 1 PROM EQU 1 PRINT NOGEN,NOMDIR,ON INCLUDE 'MaceEqu.a' ; Mace definitions INCLUDE 'PSCEqu.a' ; PSC definitions INCLUDE 'ENETEqu.a' ; Driver definitions INCLUDE 'SNMPLAP.a' ; SNMP definitions EJECT ;_______________________________________ ; ; Misc definitions ;_______________________________________ OneWdsSz EQU 8 ; single fragment wds size INTLockOut EQU $0700 ; SR value to disable ALL interrupts DMALockOut EQU $0400 ; SR value to disable PSC DMA interrupts NeedDefer EQU 5 ; bit indicates VM is running ; ееее warning, MaxChns should NOT be set > 64. It could make some calcs in the ; ееее MaceInit rtn overflow the 16 bit low-order word! MaxChns EQU 64 ; max number of chains OneChn EQU 1 ; one chain, minimum too DefChns EQU 4 ; default number of chains MaxBufpChn EQU 1023 ; max number of buffers per chain DefTxBuffs EQU 8 ; default number of xmit buffers DefRxBuffs EQU 16 ; default number of recv buffers MinBufpChn EQU 2 ; min number of buffers per chain ;MACERevA2 EQU $0941 MACERevB0 EQU $0940 MaceVars RECORD 0 ; our variables MACEmem DS.l 1 ; ptr to memory block with recv & xmit buffers RecvBuffMem DS.l 1 ; aligned recv buffer mem XmitBuffMem DS.l 1 ; aligned xmit buffer mem RecvXmitMemSz DS.l 1 ; need size of aligned mem if need to free it ChnDescrMem DS.l 1 ; recv chain descriptor mem MACEBase DS.l 1 ; MACE base address PSCBase DS.l 1 ; PSC base address DTQE DS.b dtQElSize ; Deferred task queue element DTInstalled DS.b 1 ; flag, non-zero if DT installed DS.b 1 ; fill MACEChipID DS.w 1 ; MACE revision ALIGN 4 ; еее parms saved from MaceInit call RcvRtn DS.l 1 ; users recv rtn RcvParm DS.l 1 ; users recv rtn parm XmtDnRtn DS.l 1 ; users xmit completion rtn XmtDnParm DS.l 1 ; users xmit completion rtn parm MCfg DS.l 1 ; ptr to MACE config record Dot3StatPtr DS.l 1 ; ptr to 802.3 statistics counters LAPMIBStatPtr DS.l 1 ; ptr to LAP MIB statistics counters OurAddrPtr DS.l 1 ; ptr to ethernet address MemMove DS.l 1 ; ptr to fast memory move rtn ; еее end parms ; ActRecvSet is REQUIRED since it enables the Recv processing to ensures that recv ; pkts are processed IN ORDER. ActRecvSet DS.w 1 ; offset to active recv reg set ; ActXmitSet helps, ie. not necessary, the Xmit DONE processing by pting to the "oldest" reg ; set that has completed a xmit. For cases where both sets have a xmit done int, this ; will make available the next set that can perform a xmit, the "oldest". ; NxtXmitSet is REQUIRED since it enables the Xmit PRIME processing to ensures that xmit ; pkts are sent IN ORDER. ActXmitSet DS.w 1 ; offset to active xmit reg set NxtXmitSet DS.w 1 ; offset to xmit reg set for next xmit ; еееее WARNING: Do NOT add or delete any parms in this range ; The offsets between RxChainSet0,RxChainSet1 & ; TxBuffSet0,TxBuffSet1 MUST be maintained CntlRegSetByte EQU $0001 ; AND with cntrl reg to get inactive set RegSet1Offset EQU $10 ; Reg Set1 offset from Channel base ALIGN 4 RxChainSet0 DS.l 1 ; Log addr of chain assigned to Set0 FreeRxChain DS.l 1 ; head of free recv chain list InUseRxHead DS.l 1 ; head of InUse recv chain list InUseRxTail DS.l 1 ; tail of InUse recv chain list RxChainSet1 DS.l 1 ; Log addr of chain assigned to Set1 TxBuffSet0 DS.l 1 ; Log addr of buffer assigned to Set0 FreeXmtBuff DS.l 1 ; head of free xmit buffers list InUseTxHead DS.l 1 ; head of InUse xmit buffers list InUseTxTail DS.l 1 ; tail of InUse xmit buffers list TxBuffSet1 DS.l 1 ; Log addr of buffer assigned to Set1 ; еееее END WARNING COLLCnt DS.l 1 ; recv frames with collision error ; Transmit Frame Status Register counters XmtStatINV DS.l 1 ; xmit ints with xmit status invalid XmtLCOL DS.l 1 ; late collision XmtRTRYCnt DS.l 1 ; total number of retries ; Interrupt Register counter RCVCOCnt DS.l 1 ; *256 to get # collisions on net MPCOCnt DS.l 1 ; *256 to get # of missed packets due to ; RcvOFLO, receiver disabled, or excessive ; receive frame count (RcvFC) ; RecvBerr DS.w 1 ; recv chnl bus error being processed XmitBerr DS.w 1 ; xmit chnl bus error being processed IF COUNTERS THEN RcvInts DS.l 1 ; # of times MACE int rtn called for a recvint PSCIntCnt DS.l 1 ; # of times PSC Int Rtn called MaceIntCnt DS.l 1 ; # of times MACE Int Rtn called MaceRcvCnt DS.l 1 ; # of times Deferred Recv Task called ; еееее WARNING: Do NOT add or delete any parms in this range ; The offsets between RecvSet0Cnt,RecvSet1Cnt; DTprimeSet0,DTprimeSet1; & ; XmitSet0Cnt,XmitSet1Cnt MUST be maintained RecvSet0Cnt DS.l 1 ; # of recv frames on set 0 DTprimeSet0 DS.l 1 ; # of times DT primed reg set 0 XmitSet0Cnt DS.l 1 ; # of xmit frames on set 0 NoFreeChains DS.l 1 ; # of times no free chains available RecvSet1Cnt DS.l 1 ; # of recv frames on set 1 DTprimeSet1 DS.l 1 ; # of times DT primed reg set 0 XmitSet1Cnt DS.l 1 ; # of xmit frames on set 1 ; еееее END WARNING XmitRSFull DS.l 1 ; Cnt of RegSets full on MaceXmit, -> InUse InUseXmit DS.l 1 ; Cnt of xmits done from InUse Queue InUseXmitD DS.l 1 ; Cnt of xmits removed from InUse Queue XmitPend DS.l 1 ; Cnt of DoWrite calls from MaceXmitDone noDTInstall DS.l 1 ; # of times didn't install deferred task ; since it was already installed ChnFlushed DS.l 1 ; # of times a chn was flushed RecvBerrCnt DS.l 1 ; # of bus error's on recv chnl XmitBerrCnt DS.l 1 ; # of bus error's on xmit chnl ENDIF IF BUFDEBUG THEN RecvBerrAddr DS.l 1 ; addr that caused bus error on recv chnl RecvBerrCntl DS.w 1 ; Cntl reg, look at set byte XmitBerrAddr DS.l 1 ; addr that caused bus error on xmit chnl XmitBerrCntl DS.w 1 ; Cntl reg, look at set byte XmtDnActive DS.l 1 CurrRecv DS.l 1 ENDIF IF SETDEBUG THEN hasNewPSC DS.b 1 ; non-zero = new psc, 0 = old psc ALIGN 4 ENDIF LogAddrFltr DS.b 8 ; Copy of MACE Logical Address Filter ; bit order 63-56, 55-48, ... 7-0 LAFHashTbl DS.b 64 ; Tbl of counts of number multicasts addresses ; that hash to each bit MaceVarSz EQU * ; End of variables ENDR ; ; Transmit Buffer template ; -ensure 1st one is quad-aligned and all the rest will be XmitBuff Record 0 Next DS.l 1 ; Ptr to next buffer Prev DS.l 1 ; Ptr to previous buffer LogBufPtr DS.l 1 ; Logical address of packet data area WDSptr EQU * ; Address of 1 entry WDS Len DS.w 1 ; Packet length PhyBufPtr DS.l 1 ; Physical address of packet data area Status DS.b 1 ALIGN 16 LogBufOff EQU LogBufPtr - * ; Offset from packet data area ; to Logical address of packet data area HdrBufOff EQU XmitBuff - * ; Offset from buffer header ; to packet data area Packet DS.b Max_Pkt_Size ; packet data area ALIGN 16 TxBuffSz EQU * EndR ; ; Receive Buffer template ; -ensure 1st one is quad-aligned and all the rest will be RecvBuff Record 0 MaceStat DS.b 8 ; Recv'd pkt status from Mace DS.b 8 ; fill, PSC DMAs quad-lw chunks Packet DS.b Max_Pkt_Size ; packet data area ALIGN 2048 RxBuffSz EQU * EndR ; ; Receive Chain Descriptor template ; RxChnDescr Record 0 NextChn DS.l 1 ; ptr to next chain descr PhyChnPtr DS.l 1 ; Physical address of chain LogChnPtr DS.l 1 ; Logical address of chain State DS.b 1 ; state of this chain DS.b 1 ; fill OnOffSet EQU 0 ; bit 0: 0-not on, 1-on reg set Flushed EQU 1 ; bit 1: 0-no flush, 1-flush occurred Berred EQU 2 ; bit 2: 0-no berr, 1-berr occurred Limit DS.w 1 ; # of buffers in this chain Out DS.w 1 ; # of next buffer to drain In DS.w 1 ; # of next buffer to be filled with pkt ; only valid when chain OFF reg set savedLimit DS.w 1 ; only needed after flush done on chain RxChnDescrSz EQU * EndR EJECT STRING PASCAL MACHINE MC68020 MaceData PROC ENTRY MaceVarPtr MaceVarPtr Dc.l 1 ; Contains ptr to my variables ENDP ;________________________________________________________________________ ; ; RecoverXmitBuffs - move any xmit buffers from DMA chnl to free queue. ; ; Call: A2 - globals ; Return: none ; ;________________________________________________________________________ RecoverXmitBuffs PROC WITH MACERegs,MaceVars,PSC_DMA_CHNL ; Put transmit buffs back on freelist MoveQ #0, D0 ; reg set 0 offset @chgsets Move.l TxBuffSet0(A2,D0), D1 Beq.s @nobuff Clr.l TxBuffSet0(A2,D0) MoveA.l D1, A0 Move.l FreeXmtBuff(A2), XmitBuff.Next(A0) ; Make us pt to head of freelist Move.l A0, FreeXmtBuff(A2) ; Make us head of freelist @nobuff BChg #4, D0 Beq.s @chgsets Rts ENDP ;________________________________________________________________________ ; ; ResetXmitChnl - reset PSC's MACE DMA xmit channel, reset MACE xmit FIFO, ; move any xmit buffers from DMA chnl to free queue. ; ; Call: A2 - globals ; Return: none ; ;________________________________________________________________________ ResetXmitChnl PROC WITH MACERegs,MaceVars,PSC_DMA_CHNL ; Reset PSC DMA xmit chnl ; -leaves chnl paused ; -clears set ENABLE's MoveA.l PSCBase(A2), A0 Move #(1< Mace Recv DMA channel @initset Move.l FreeRxChain(A2), D0 ; Dequeue next available recv chain Beq.s @nocando ; none available, leave MoveA.l D0, A1 Move.l NextChn(A1), FreeRxChain(A2) Clr.l NextChn(A1) IF SETDEBUG THEN Bsr InitRecv ; Prime Register Set ELSE Bsr.s InitRecv ; Prime Register Set ENDIF BChg #4, D4 ; Toggle reg sets Beq.s @initset ; if D2 was $0 (set 0), init set 1 @nocando MoveM.l (SP)+, A3/D4 Rts ENDP EJECT ;________________________________________________________________________ ; ; PrimeRecv - Prime reg set with chain from free queue ; ; Call: ; A2 - our variables ; A3 - Receive DMA Channel Reg Set base address ; D4 - Register set offset ; ; Return: none ; ; Notes: ; -can trash C scratch regs: A0-A1,D0-D2 ;________________________________________________________________________ PrimeRecv PROC WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr MoveA.l RxChainSet0(A2,D4), A0 ; get active chain descriptor ptr IF BUFDEBUG THEN Move.l A0, D1 Bne.s @noprob _Debugger @noprob ENDIF Clr.l RxChainSet0(A2,D4) ; indicate no chain on reg set BClr #OnOffSet, State(A0) ; indicate this chain NOT on reg set ; ; Put this recv chain on InUse queue ; Move.l InUseRxTail(A2), D1 ; Something on the queue? Bne.s @61 ; Yes ; Empty queue Move.l A0, InUseRxTail(A2) ; Point tail at us Move.l A0, InUseRxHead(A2) ; Point head at us Bra.s @62 @61 ; Items on queue Move.l D1, A1 ; Get tail Move.l A0, NextChn(A1) ; Put on end of queue Move.l A0, InUseRxTail(A2) ; Make tail pt to us @62 Clr.l NextChn(A0) ; ; Setup offset to active chain for DT. Since all buffers in chain are full or we flushed, ; PSC will have switched to other reg set. ; BChg #4, D4 ; toggle reg set offset Move D4, ActRecvSet(A2) ; chg offset to active reg set BChg #4, D4 ; toggle back reg set offset Tst.b RecvBerr(A2) ; are we're processing buserror? Bne.s @bye ; yes, leave ; ; Dequeue next available recv chain ; Move.l FreeRxChain(A2), D1 IF COUNTERS THEN Bne.s @getfreechain AddQ.l #1, NoFreeChains(A2) ; no chains available Bra.s @bye @getfreechain ELSE Beq.s @bye ; no chains available ENDIF MoveA.l D1, A1 ; A1->addr of recv chain descriptor Move.l NextChn(A1), FreeRxChain(A2) ; Dequeue from free list Clr.l NextChn(A1) Bsr InitRecv ; prime reg set with this chain @bye Rts ; leave ENDP EJECT ;________________________________________________________________________ ; ; ResetMACE - Reset PSC & MACE FIFOs and disable recv & xmit paths and reset MACE ; ; Call: A2 - drvr vars ; ; Return: none ; ; Destroys: A1,D0,D1 ; ;________________________________________________________________________ ResetMACE PROC EXPORT WITH MACERegs,MaceVars,PSC_DMA_CHNL ; reset & disable MACE -> PSC receive path MoveA.l MACEBase(A2), A0 ; A0-> base address of MACE regs MoveA.l PSCBase(A2), A1 ; A1-> base address of PSC regs Move.b #0, MACE_MAC_CNFG(A0) ; Disable MACE recv, xmit, et. al. Move.b MACE_FIFO_CNFG(A0), D0 ; Get current FIFO config OrI.b #(1< MACE transmit path Move #(1< PSC Interrupt table ptr ENDWITH MoveQ #0, D0 Move.l D0, MACE_RECVhndlr(A0) Move.l D0, MACE_RECVparm(A0) Move.l D0, MACE_XMIThndlr(A0) Move.l D0, MACE_XMITparm(A0) ; Install Mace Interrupt handler, called at Level 3 Move.l PSCBase(A2), A1 ; Base address of PSC Move.b #(1< my variables ; ; Return: ; none ; ; Uses: ; A1, D0 ; ; The LAF can not be updated while MACE recv is enabled. Disable MACE pkt ; reception. If frames in MACE Recv FIFO, reset MACE Recv FIFO (possible pkt ; loss), flush PSC recv FIFO, and reprime affected DMA Reg. Set. Finally, ; update the LAF. ;________________________________________________________________________ WriteLAF PROC WITH MACERegs,MaceVars,PSC_DMA_CHNL MoveA.l MACEBase(A2), A1 Move.b MACE_MAC_CNFG(A1), -(SP) ; Save current config Move.b #(1< copy of logical address filter Move.b #(1< 6 bit hash into LAF AddQ.b #1, (LAFHashTbl,A2,D0) ; Inc. # of multi's with this hash CmpI.b #1, (LAFHashTbl,A2,D0) ; Multiaddr hash bit already in LAF? Bhi @bye ; yes, do nothing Lea LogAddrFltr(A2), A0 ; A0-> copy of log. addr. filter Cmp.b #31, D0 ; Hash > 31? Bhi.s @b63to32 ; yes Move.l 4(A0), D1 ; no, get LAF bits 31-0 BSet.l D0, D1 ; Is this hash bit already set? Bne @bye ; yes, nothing to do Move.l D1, 4(A0) ; Save modified LAF bits 31-0 Bra.s @doit @b63to32 Sub.b #32, D0 ; Convert hash for use on LAF bits 63-32 Move.l (A0), D1 ; Get LAF bits 63-32 BSet.l D0, D1 ; Is this hash bit already set? Bne @bye ; yes, nothing to do Move.l D1, (A0) ; Save modified LAF bits 63-32 @doit Bsr WriteLAF ; Write the new LAF @bye Move.l (SP)+, A2 ; Restore used C regs Rts ENDP EJECT ;___________________________________________________________________________ ; ; MaceDelMulti - Delete a multicast address HASH from the LAF ; ; Call: ; D1 = first two bytes of address ; D3 = last four bytes of address ; ; Return: ; none ; ; Computes the hash for this multicast address and decrements the LAF ; Table hash count for the given Multicast address. If new hash count = 0, ; clears appropriate bit in MACE LAF. ; Depends on caller to ensure not called for a multicast's hash that hasn't ; already been inc'd in LAFHashTbl. ;___________________________________________________________________________ MaceDelMulti PROC EXPORT WITH MACERegs,MaceVars Move.l A2, -(SP) ; Save used C regs MoveA.l MaceVarPtr, A2 ; Get ptr to my vars Bsr DoCRC ; D0-> 6 bit hash into LAF SubQ.b #1, (LAFHashTbl,A2,D0) ; Dec. # of multi's with this hash Bne @bye ; Do nothing if hash table cnt non-zero ; Clear this bit in LAF since no other ; multiaddr's hash to this bit Lea LogAddrFltr(A2), A0 ; A0-> copy of log. addr. filter Cmp.b #31, D0 ; Hash > 31? Bhi.s @b63to32 ; yes Move.l 4(A0), D1 ; no, get LAF bits 31-0 BClr.l D0, D1 ; Clear this hash bit IF DEBUG THEN Beq @huh ; if LAFHashTbl correct, D1 should ELSE ; have D0 bit set! Beq @bye ; do nothing hash bit already clear! ENDIF Move.l D1, 4(A0) ; Save modified LAF bits 31-0 Bra.s @doit @b63to32 Sub.b #32, D0 ; Convert hash for use on LAF bits 63-32 Move.l (A0), D1 ; Get LAF bits 63-32 BClr.l D0, D1 ; Clear this hash bit IF DEBUG THEN Beq @huh ; if LAFHashTbl correct, D1 should ELSE ; have D0 bit set! Beq @bye ; do nothing hash bit already clear! ENDIF Move.l D1, (A0) ; Save modified LAF bits 63-32 @doit Bsr WriteLAF ; Write the new LAF @bye Move.l (SP)+, A2 ; Restore used C regs Rts IF DEBUG THEN @huh _Debugger ; nothing to do 'cause hash bit Bra.s @bye ; was already clear ENDIF ENDP EJECT ;___________________________________________________________________________ ; ; PrimeXmitRS - Prime Reg Set with transmit packet info. ; ; Call: ; 4(SP) - xmit buffer ptr ; A2 - our vars ; ; Return: ; If xmit register sets are full, return CC==NE; else, CC==EQ. ; Notes: ; Called both on normal writes (with level 4 interrupts disabled) ; AND on write completions (interrupt level 4) ;___________________________________________________________________________ PrimeXmitRS PROC XmitPrm RECORD 4 XmitPtr DS.l 1 ; Transmit buffer ptr ParmSz EQU * ENDR WITH MACERegs,MaceVars,PSC_DMA_CHNL,LAPMIBStats Move.l XmitPrm.XmitPtr(SP), D1 ; D1 - xmit buffer ptr ; Move SR,-(SP) ; Save interrupt mask level ; OrI #DMALockOut, SR ; Disable DMA ints. Move NxtXmitSet(A2), D2 ; get offset to next reg set to xmit on Lea TxBuffSet0(A2), A1 Tst.l (A1,D2) ; Can we use this reg set? Beq.s @cont2 ; yes ; Move (SP)+,SR ; Restore int. mask level MoveQ #-1, D0 ; Set CC's Rts ; Return ; ; Initialize Xmit DMA Channel Register Set ; @cont2 MoveA.l PSCBase(A2), A0 Lea PSC_MACE_XMIT(A0), A0 ; A0-> Xmit DMA Channel base addr Move.l D1, (A1,D2) ; Indicate (D1) is active buff on reg set MoveA.l D1, A1 ; A1->xmit buffer IF SETDEBUG THEN IF not SETDEBUGFAIL THEN Tst.b hasNewPSC(A2) Beq.s @a01 ; go to old PSC patch Move.l XmitBuff.PhyBufPtr(A1), Addr(A0,D2) ; Set DMA dest addr Bra.s @aaa1 @a01 ENDIF Move.l XmitBuff.PhyBufPtr(A1), D0 And.l #$FFFFFFF0, D0 ; line aligned addr @a1 Move.l XmitBuff.PhyBufPtr(A1), Addr(A0,D2) ; Set DMA dest addr Move.l Addr(A0,D2), D1 And.l #$FFFFFFF0, D1 ; line aligned addr Cmp.l D0, D1 IF SETDEBUGFAIL THEN Beq.s @aa1 _Debugger Bra.s @a1 @aa1 ELSE Bne.s @a1 @aaa1 ENDIF ELSE Move.l XmitBuff.PhyBufPtr(A1), Addr(A0,D2) ; Set DMA dest addr ENDIF MoveQ #0, D0 Move.w XmitBuff.Len(A1), D0 ; Get DMA byte count (word) IF SETDEBUG THEN IF not SETDEBUGFAIL THEN Tst.b hasNewPSC(A2) Beq.s @a02 ; go to old PSC patch Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long) Bra.s @aaa2 @a02 ENDIF @a2 Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long) Move.l Cnt(A0,D2), D1 Cmp.l D0, D1 IF SETDEBUGFAIL THEN Beq.s @aa2 _Debugger Bra.s @a2 @aa2 ELSE Bne.s @a2 @aaa2 ENDIF ELSE Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long) ENDIF BTst #0, XmitBuff.Packet(A1) ; xmiting a multi/bcast? MoveA.l LAPMIBStatPtr(A2), A1 Bne.s @30 AddQ.l #1, ifOutUcastPkts(A1) ; inc. non-multi/bcast cntr Bra.s @31 @30 AddQ.l #1, ifOutNUcastPkts(A1) ; inc. multi/bcast cntr @31 Add.l D0, ifOutOctets(A1) ; inc. sent octet cntr IF SETCSDEBUG THEN IF not SETCSDEBUGFAIL THEN Tst.b hasNewPSC(A2) Beq.s @a03 ; go to old PSC patch Move #(1< MoveQ #0, D0 ; Set CC's Rts ; Return ENDP EJECT ;___________________________________________________________________________ ; ; RecvBusErr - handle bus errors on PSC's MACE DMA receive channel ; ; Call: ; A2 - our variables ; D1 - Receive DMA Channel control register value ; ; Return: ; none ; Notes: ; Should never get called! ;___________________________________________________________________________ RecvBusErr PROC WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr ST RecvBerr(A2) ; indicate we're processing buserror IF COUNTERS THEN AddQ.l #1, RecvBerrCnt(A2) ENDIF MoveA.l MACEBase(A2), A0 Move.b MACE_MAC_CNFG(A0), D0 ; get current config Move.b D0, -(SP) ; save it BClr #ENRCV, D0 Move.b D0, MACE_MAC_CNFG(A0) ; Disable recv IF BUFDEBUG THEN Move D1, RecvBerrCntl(A2) ; save chnl control reg MoveQ #0, D0 ; assume set 0 BTst #0, D1 ; which set had bus error? Beq.s @set0 BChg #4, D0 ; chng to set 1 @set0 MoveA.l PSCBase(A2), A0 Lea PSC_MACE_RECV(A0), A0 ; A0-> base addr of recv DMA chnl Move.l Addr(A0,D0), RecvBerrAddr(A2) ; save addr of bus error ENDIF ; Reset MACE FIFO Bsr FlushRecvRegSet ; and put chain in InUse (PrimeRecv). ; NOTE: PrimeRecv toggles ActRecvSet(A2) Bsr FlushRecvChn ; put other chain in InUse (PrimeRecv). MoveA.l PSCBase(A2), A0 Move #(1< base addr of xmit DMA chnl Move.l Addr(A0,D0), XmitBerrAddr(A2) ; save addr of bus error ENDIF ; Reset PSC's MACE DMA xmit chnl and reset MACE xmit FIFO Bsr ResetXmitChnl ; and put any xmit buffs on free queue. Clr.b XmitBerr(A2) ; indicate we're DONE processing buserror Rts ENDP EJECT ;___________________________________________________________________________ ; ; MaceXmit - Calls PrimeXmitRS to prime Reg Set with transmit packet info. ; If xmit register sets are full, put xmit buffer ptr on tail ; of xmit InUse queue. ; ; Call: ; 4(SP) - WDS ptr ; ; Return: ; D0 = error code; nobuff - temporarily out of xmit buffers ; eLenErr - sum of data in WDS > max. pkt size ; noErr - primed reg set with xmit pkt or put pkt ; on xmit InUse queue ; Notes: ; Called both on normal writes AND write completion (interrupt level 4) ;___________________________________________________________________________ MaceXmit PROC EXPORT WDSPrm RECORD 4 ; Return address WDSPtr DS.l 1 ; Write Data Structure ptr ParmSz EQU * ENDR WITH MACERegs,MaceVars Move.l WDSPrm.WDSPtr(SP), D2 ; Get WDS ptr Move.l A2, -(SP) ; Save C regs MoveA.l MaceVarPtr, A2 ; Get ptr to my vars Move SR,-(SP) ; Save interrupt mask level OrI #DMALockOut, SR ; Disable DMA ints. Move.l FreeXmtBuff(A2),D1 ; get a buffer pointer Bne.s @haveBuff Move (SP)+,SR ; Restore int. mask level MoveA.l (SP)+, A2 ; Restore C regs MoveQ #nobuff,D0 ; Set no xmit buff available error Rts ; return to caller @haveBuff MoveA.l D1, A1 ; A1->buffer IF BUFDEBUG THEN CmpA.l XmitBuff.Next(A1), A1 ; linked to myself? Bne.s @dok1 _Debugger ; yes, oooppppsss! @dok1 CmpA.l InUseTxHead(A2), A1 ; on Free as well as InUse? Bne.s @dok2 _Debugger ; yes, oooppppsss! @dok2 ENDIF Move.l XmitBuff.Next(A1),FreeXmtBuff(A2) ; unlink buffer from free list Clr.l XmitBuff.Next(A1) Move (SP)+,SR ; Restore int. mask level ; ; Total the length and make sure it's valid ; Move.l A1, -(SP) ; save buffer pointer for later Move.l A4, -(SP) ; save non-interrupt scratch reg. Clr.w XmitBuff.Len(A1) ; init len Move.l D2, A4 ; A4-> WDS @1 MoveQ #0,D0 Move.w (A4), D0 ; get this wds entry length Beq.s @2 ; all done AddQ.w #6, A4 ; inc to next wds entry length Add.w D0, XmitBuff.Len(A1) ; sum the length Bra.s @1 ; look for more @2 Move.w XmitBuff.Len(A1),D1 ; get single fragment length Sub.w #EHdrSize,D1 ; Subtract out header bytes Cmp.w #EMaxDataSz,D1 ; Check the data's length Bls.s @cont ; Branch if ok ; ; Length error, relink buffer onto free list and return error ; MoveA.l (SP)+, A4 ; restore non-interrupt scratch reg. MoveA.l (SP)+, A1 ; Pop buff ptr Move SR,-(SP) ; Save interrupt mask level OrI #DMALockOut, SR ; Disable DMA ints. Move.l FreeXmtBuff(A2), XmitBuff.Next(A1) ; link buffer back into free list Move.l A1, FreeXmtBuff(A2) Move (SP)+,SR ; Restore int. mask level MoveA.l (SP)+, A2 ; Restore C regs MoveQ #eLenErr,D0 ; Set length error Rts ; Return it ; ; Copy WDS data to our Xmit buffer ; @cont MoveA.l XmitBuff.LogBufPtr(A1), A1 ; A1->packet data MoveA.l D2, A4 ; A4-> WDS @3 Move.w (A4)+, D0 ; last WDS entry? Beq.s @4 ; yes, all done MoveA.l (A4)+, A0 ; get pointer to the data ; A0->source, A1->dest, D0=len MoveM.l A1/D0,-(SP) ; save buff ptr and len Jsr ([MemMove,A2]) ; move the data MoveM.l (SP)+,A1/D0 AddA.l D0, A1 ; update buff ptr Bra.s @3 ; look for more @4 MoveA.l (SP)+, A4 ; restore non-interrupt scratch reg. ; (SP) -> Xmit buffer ptr pushed earlier MoveA.l (SP)+, A1 ; Pop buff ptr Move SR,-(SP) ; Save interrupt mask level OrI #DMALockOut, SR ; Disable DMA ints. Move.l A1, -(SP) ; Push buff ptr Jsr PrimeXmitRS Bne.s @regsetsfull AddQ #4, SP ; Strip parms Move (SP)+, SR ; MoveA.l (SP)+, A2 ; Restore C regs MoveQ #0, D0 ; Set return code & CC's Rts ; Return ; ; We were NOT able to queue this buffer in a reg set ; Put this xmit buffer on xmit InUse queue ; @regsetsfull IF COUNTERS THEN AddQ.l #1, XmitRSFull(A2) ENDIF MoveA.l (SP)+, A1 ; Restore xmit buffer ptr ; Move SR,-(SP) ; Save interrupt mask level ; OrI #DMALockOut, SR ; Disable DMA ints. Move.l InUseTxTail(A2), D1 ; Something on the queue? Bne.s @11 ; Yes, branch ; Empty queue Move.l A1, InUseTxTail(A2) ; Point tail at us Move.l A1, InUseTxHead(A2) ; Point head at us Bra.s @22 @11 ; Items on queue Move.l D1, A0 ; Get tail Move.l A1, XmitBuff.Next(A0) ; Put on end of queue Move.l A1, InUseTxTail(A2) ; Make tail pt to us @22 Clr.l XmitBuff.Next(A1) Move (SP)+,SR ; Restore int. mask level MoveA.l (SP)+, A2 ; Restore C regs MoveQ #0, D0 ; Set return code & CC's Rts ; Return ENDP EJECT IF PROM THEN ;___________________________________________________________________________ ; ; MACEXmitProm - xmit packet directly from user's buffer ; ; Call: ; 4(SP) - xmit buffer ptr ; ; Return: ; If xmit register sets are full, return CC==NE; else, CC==EQ. ; Notes: ; Called both on normal writes AND write completion (interrupt level 4) ;___________________________________________________________________________ MACEXmitProm PROC EXPORT XmitPrm RECORD {A6Link} LocalSize EQU * A6Link DS.l 2 XmitPtr DS.l 1 ; Transmit buffer ptr XmitLen DS.w 1 ; Transmit buffer len ENDR WITH MACERegs,MaceVars,PSC_DMA_CHNL,LAPMIBStats,XmitPrm Link A6,#LocalSize ; Save A6 MoveM.l A2, -(SP) MoveA.l MaceVarPtr, A2 ; Get ptr to my vars Move SR,-(SP) ; Save interrupt mask level OrI #DMALockOut, SR ; Disable DMA ints. Move NxtXmitSet(A2), D2 ; get offset to next reg set to xmit on MoveA.l PSCBase(A2), A0 Lea PSC_MACE_XMIT(A0), A0 ; A0-> Xmit DMA Channel base addr @chkxmtdn Move CmdStat(A0,D2), D0 ; Get DMA status (word) Btst #TERMCNT, D0 ; xfer in progress? Beq.s @chkxmtdn ; yes, wait for it to complete ; no, we can use this set ; ; Initialize Xmit DMA Channel Register Set ; Move.l XmitPtr(A6), A1 ; A1 - user xmit buffer ptr IF SETDEBUG THEN IF not SETDEBUGFAIL THEN Tst.b hasNewPSC(A2) Beq.s @a01 ; go to old PSC patch Move.l A1, Addr(A0,D2) ; Set DMA dest addr to user buff ptr Bra.s @aaa1 @a01 ENDIF Move.l A1, D0 And.l #$FFFFFFF0, D0 ; line aligned addr @a1 Move.l A1, Addr(A0,D2) ; Set DMA dest addr Move.l Addr(A0,D2), D1 And.l #$FFFFFFF0, D1 ; line aligned addr Cmp.l D0, D1 IF SETDEBUGFAIL THEN Beq.s @aa1 _Debugger Bra.s @a1 @aa1 ELSE Bne.s @a1 ENDIF @aaa1 ELSE Move.l A1, Addr(A0,D2) ; Set DMA dest addr to user buff ptr ENDIF MoveQ #0, D0 Move XmitLen(A6), D0 ; Get pkt len (word) IF SETDEBUG THEN IF not SETDEBUGFAIL THEN Tst.b hasNewPSC(A2) Beq.s @a02 ; go to old PSC patch Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long) Bra.s @aaa2 @a02 ENDIF @a2 Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long) Move.l Cnt(A0,D2), D1 Cmp.l D0, D1 IF SETDEBUGFAIL THEN Beq.s @aa2 _Debugger Bra.s @a2 @aa2 ELSE Bne.s @a2 ENDIF @aaa2 ELSE Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long) ENDIF BTst #0, (A1) ; xmiting a multi/bcast? MoveA.l LAPMIBStatPtr(A2), A1 Bne.s @30 AddQ.l #1, ifOutUcastPkts(A1) ; inc. non-multi/bcast cntr Bra.s @31 @30 AddQ.l #1, ifOutNUcastPkts(A1) ; inc. multi/bcast cntr @31 Add.l D0, ifOutOctets(A1) ; inc. sent octet cntr Move #(1< buffer to xmit (InUseTxHead) Jsr PrimeXmitRS MoveA.l (SP)+, A1 ; A1-> buffer just xmitted MoveA.l (SP)+, A0 ; Restore MaceVarPtr IF BUFDEBUG THEN CmpA.l XmitBuff.Next(A1), A1 ; linked to myself? Bne.s @dok3 _Debugger ; oooppppsss! @dok3 CmpA.l FreeXmtBuff(A0), A1 ; on free list too? Bne.s @dok4 _Debugger ; oooppppsss! @dok4 Move.l FreeXmtBuff(A0), D1 Cmp.l InUseTxHead(A0), D1 ; on both? Bne.s @dok5 _Debugger ; oooppppsss! @dok5 ENDIF IF COUNTERS THEN AddQ.l #1, InUseXmitD(A0) ENDIF @inuseempty Move.l XmtDnRtn(A0), D0 Beq.s @skip ; no xmit completion rtn Move.l A0, -(SP) ; Save A0 Move.l XmtDnParm(A0), -(SP) ; Push user parm MoveA.l D0, A0 Jsr (A0) ; Call user xmit completion rtn AddQ #4, SP ; Strip parms MoveA.l (SP)+, A0 ; Restore A0 @skip IF BUFDEBUG THEN SubQ.l #1, XmtDnActive(A0) ENDIF Rts ENDP EJECT ;___________________________________________________________________________ ; ; MaceRecv - Deferred Task Packet receive routine ; ; Call: ; A1 - our variables ; Received packet(s) in buffers in chain(s) on InUse Queue and, perhaps, ; in buffers in chain(s) on Register Sets. ; ; Return: ; Empty InUse Queue ; ; Destroys: ; ; Calls: ; Calls user's handler to receive packet. ; ; Notes: ; Since MaceRecv runs under DTMgr, more packets can arrive and ; get queued in chains on InUse queue while we're running. So, ; we'll loop using InUseRxHead to dequeue and process received packets. ; Once we've drained all chains from InUse, we check for packets in the ; chain on the active reg set. ; Installed via PSCInterrupt, called via Deferred Task Mgr. ; When the chain is ON the reg set, we compare Out & In, where ; In = Limit - Cnt. When the chain is on InUse, we compare Out & Limit. ;___________________________________________________________________________ MaceRecv PROC WITH MACERegs,MaceVars,PSC_DMA_CHNL,RecvBuff,RxChnDescr WITH Dot3StatsEntry,LAPMIBStats MoveM.l A2-A4/D3-D4,-(SP) ; save non-scratch regs Move.l A1, A2 ; A2 -> Mace vars IF COUNTERS THEN AddQ.l #1, MaceRcvCnt(A2) ENDIF ; ; Check InUse queue for recv chains ; Move SR,-(SP) ; Save interrupt mask level OrI #DMALockOut, SR ; Disable DMA ints. @recvnext Move.l InUseRxHead(A2), D0 ; recv chain(s) in InUse? Beq @chksets ; no MoveA.l D0, A4 Move.l NextChn(A4), D0 ; Another chain in queue? Bne.s @1 ; yes Move.l D0, InUseRxTail(A2) ; Clear tail @1 Move.l D0, InUseRxHead(A2) ; Make head pt to next entry Clr.l NextChn(A4) Move (SP)+, SR ; Restore SR IF BUFDEBUG THEN Move.l A4, CurrRecv(A2) ENDIF ; ; Loop until Out == Limit, delivering packets to .ENET ; @dochain Move Limit(A4), D0 Cmp Out(A4), D0 ; are there packets to process? Beq.s @chaindone ; no Bsr GetPkt ; Get pkt at Out and deliver it Bra.s @dochain ; check for more pkts @chaindone ; ; Queue the now empty recv chain onto head of Free list. First check if either reg set ; needs to be primed since there may have been NO freechains when the DMA interrupt ; handler wanted to prime the reg set. ; MoveA.l A4, A1 ; A1-> now empty chain descr Move SR,-(SP) ; Save interrupt mask level OrI #DMALockOut, SR ; Disable DMA ints. Move ActRecvSet(A2), D4 ; get offset to active reg set Move #1, D3 ; init loop cntr MoveA.l PSCBase(A2), A3 Lea PSC_MACE_RECV(A3), A3 ; A3-> Recv Channel base address @chkset Tst.l RxChainSet0(A2,D4) ; Reg Set0/1 need priming? Bne.s @chk1 ; no Bsr InitRecv ; Prime it IF COUNTERS THEN AddQ.l #1, (DTprimeSet0,A2,D4) ENDIF Bra @recvnext ; Go check InUse list @chk1 BChg #4, D4 ; Toggle reg sets ; DBra D3, @chkset ; Put chain on free list Move.l FreeRxChain(A2), NextChn(A1) ; Make us pt to current head of free list Move.l A1, FreeRxChain(A2) ; Make us new head of free list Bra @recvnext ; Go check InUse list ; ; We've drained all packets in chains on InUse queue, now check for packets ; in chains still on reg sets. We know ActRecvSet is valid since we just checked ; InUse queue and DMA ints are still masked. ActRecvSet assures us we'll process ; pkts in the correct order; ie. InUse head to tail, then ActRecvSet. @chksets Move ActRecvSet(A2), D4 ; get offset to active reg set MoveA.l RxChainSet0(A2,D4), A4 ; get active chain descr MoveA.l PSCBase(A2), A3 Lea PSC_MACE_RECV(A3), A3 ; A3-> Recv Channel base address @domore ; We want to get Limit while ints are off to ensure we calculate "In" with the "real" ; limit and not with the "flush" value of limit. We want to get Cnt while ints are off to ; ensure Cnt value is Cnt for our chain. If ints we're on, we could take an int, reprime ; the reg set with a new chain, and Cnt would no longer refer to our chain. Move Limit(A4), D1 ; get Limit Move.l Cnt(A3,D4), D2 ; get current cnt ; Here, we don't care any more if chain is on or off reg set. We can recv the pkt at Out. ; However, we'll keep ints masked until after we clear DTInstalled. This prevents a race cond. ; where a recv/xmit int could occur between here and @exit. It could happen when we're here ; and there's 1 buffer left in chain (Out = Limit - 1). The int. hnldlr (ChkRecv) could run ; and would clear ints on the set then NOT install us since we're already installed. We'd ; leave but no more ints will happen on the set. If the other set is not primed, we'll never ; get called again. Sub D2, D1 ; D1 = In = Limit - Cnt IF BUFDEBUG THEN Move D1, In(A4) ; save In ENDIF Cmp Out(A4), D1 ; Out == In? Beq.s @exit ; yes, no more packets to recv Move (SP), SR ; Restore int mask level Bsr.s GetPkt ; Get pkt at Out and deliver it ; ; Verify chain we're processing is still on reg set. If not, its moved to InUse queue. ; OrI #DMALockOut, SR ; Disable DMA ints. Btst #OnOffSet, State(A4) ; Is chain still on reg set? Beq @recvnext ; no, go drain it from InUse Bra.s @domore ; yes, go check for more pkts @exit Clr.b DTInstalled(A2) ; Indicate Deferred Task NOT Installed Move #(1< MoveA.l D0, A0 ; A0-> segment in chain Lea MaceStat(A0), A1 ; pt to Mace status MoveA.l LAPMIBStatPtr(A2), A5 ; pt to LAP stats MoveA.l Dot3StatPtr(A2), A6 ; pt to DOT3 stats ; ; Retrieve status bytes from beginning of buffer. Each status byte is present in ; the high and low bytes of a word. There are 4 status bytes, so there are 8 bytes ; of status. ; Move (A1)+, D2 ; Get Byte Cnt(7-0) MoveQ #0, D1 Move.b D2, D1 Add.l D1, ifInOctets(A5) Move (A1)+, D1 ; Get Status(in bits 7-4) and ; Byte Cnt(11-8) in bits 3-0 Move.b D1, D0 AndI #(1<0 Beq.s @mpci ; no AddQ.l #1, RCVCOCnt(A1) @mpci BTst #MPCO, D0 ; Missed packet count interrupt? This int. ; indicates MPC reg. rolled over from 255->0 Beq.s @cerr ; no AddQ.l #1, MPCOCnt(A1) Add.l #256, ifInErrors(A2) @cerr BTst #CERR, D0 ; Collision error interrupt? Beq.s @babl ; no AddQ.l #1, dot3StatsSQETestErrors(A3) AddQ.l #1, ifOutErrors(A2) @babl BTst #BABL, D0 ; Babble error interrupt? IF COUNTERS THEN Beq.s @chkrcv ; no AddQ.l #1, dot3StatsFrameTooLongs(A3) AddQ.l #1, ifOutErrors(A2) @chkrcv BTst #RCVINT, D0 ; Recv int? Beq.s @done ; no, check ints. AddQ.l #1, RcvInts(A1) ELSE Beq.s @done ; no AddQ.l #1, dot3StatsFrameTooLongs(A3) AddQ.l #1, ifOutErrors(A2) ENDIF @done MoveM.l (SP)+, A0/A2/A3/D1 MoveQ #1, D0 ; Indicate int. was serviced RtS ; Return from MaceInterrupt ENDP EJECT ;___________________________________________________________________________ ; ; PSCInterrupt - Process DMA Interrupt from PSC ; ; Call: ; A1 - our variables ; ; Return: ; D0=1, Indicate Interrupt was serviced ; ; Destroys: ; A2 - our variables ; A3 - Receive or Transmit DMA Channel base address ; D4.b - Register Set offset, 0 or $10 ; ; Calls: ; PrimeRecv - reprime a Recv DMA reg set ; MaceXmitDone - read Xmit status and reprime Xmit DMA regs if needed ; ; RePrime Receive and Transmit Register Sets. Install Deferred Task to ; process Received Packets and Transmit Completions. ;___________________________________________________________________________ PSCInterrupt PROC WITH MACERegs,MaceVars,PSC_DMA_CHNL MoveM.l A0/A2-A3/D1-D4, -(SP) ; Save regs Move.l A1, A2 ; A2 -> our variables IF COUNTERS THEN AddQ.l #1, PSCIntCnt(A2) ENDIF ; ; Check for packet in Receive DMA Channel ; ; If bus error, go handle it, make sure DT installed, then check for xmit done int. ; Else ; If set's chain is full, reprime set and install DT. Loop back and check the other ; set, ONLY so we can, if needed, disable ints for this set. Note: DT checks ; "active set" after draining InUse. ; Else set's chain is NOT full, disable ints for set, install DT, and leave. ; ChkRecv MoveA.l PSCBase(A2), A0 Move PSC_MACE_RECV_CNTL(A0), D1 BTst #BERR, D1 ; Bus Error on recv channel? Beq.s @noberr ; no Bsr RecvBusErr ; go handle it Bra.s @rcvberrcont ; go make sure DT installed @noberr BTst #CIRQ, D1 ; Interrupt on recv channel? Beq.s ChkXmitDone ; no, check xmit channel Lea PSC_MACE_RECV(A0), A3 ; A3-> Recv Channel base address Move ActRecvSet(A2), D4 ; D4-> offset to reg set IF COUNTERS THEN AddQ.l #1, (RecvSet0Cnt,A2,D4) ; inc count for set ENDIF IF DEBUG THEN Move CmdStat(A3,D4), D1 ; Get command/status BTst #IF, D1 ; Recv packet? Bne.s @ok1 _Debugger ; no, actrecvset screwed up? @ok1 ENDIF Move #(1<deferred task queue element MoveA.l JDTInstall, A1 Jmp (A1) ; install deferred task ELSE Move SR, -(SP) Move #$0300, D0 ; Disable ▓ l3 ints. _SETINTMASK D0 Lea MaceRecv, A0 MoveA.l A2, A1 Jsr (A0) Move (SP)+, SR ENDIF @donerecv Rts @chnfull Bsr PrimeRecv ; All of chain's buffers are full, ; reprime reg set with new chain Bsr.s @installDT ; make sure DT installed Bra.s ChkRecv ; go check other reg set ; ; Check for Transmit Completion Interrupt ; ChkXmitDone MoveA.l PSCBase(A2), A0 Move PSC_MACE_XMIT_CNTL(A0), D1 BTst #BERR, D1 ; Bus Error on xmit channel? Beq.s @noberr ; no Bsr XmitBusErr ; yes, go handle it Bra.s @donePSCInt @noberr BTst #CIRQ, D1 ; Interrupt on xmit channel? Beq.s @donePSCInt ; no, leave Lea PSC_MACE_XMIT(A0), A3 ; A3-> Xmit Channel base address Move ActXmitSet(A2), D4 ; get offset to active reg set IF COUNTERS THEN AddQ.l #1, (XmitSet0Cnt,A2,D4) ; inc count for set ENDIF IF DEBUG THEN Move CmdStat(A3,D4), D1 ; Get command/status BTst #IF, D1 ; Xmit done packet? Bne.s @ok1 _Debugger ; no, ActXmitSet screwed up? @ok1 ENDIF Move #(1<proc to move memory FAST ; IPSize EQU * ; ; Return: ; D0 = openErr (-23) or mFulErr (-41) ;___________________________________________________________________________ MaceInit PROC EXPORT parms RECORD {A6Link} LocalSize EQU * A6Link DS.l 2 ; link and return address initp DS MACEInitParms ; parameters passed to us ENDR IMPORT TranslateAddress, GetMemory, FreeMemory WITH parms,initp,MACERegs,MaceVars,PSC_DMA_CHNL,PSC_INT_TBL Link A6,#LocalSize ; Save A6 MoveM.l A2-A4/D3-D5,-(SP) ; Save regs WITH GetMem Sub.l #GetMemSz, SP ; room for results Move.l #MaceVarSz, memsize(SP) ; requested memory size Move.l #0, memoptions(SP) ; do NOT want memory locked, ; contiguous, and non-cacheable Pea MaceVarPtr Move.l (SP)+, memhndl(SP) Lea GetMemory, A0 Jsr (A0) ; get memory Add.l #GetMemSz, SP ; pop parms Blt @InitError ; bra if error ENDWITH MoveA.l MaceVarPtr, A2 ; get ptr to my vars Move.l UnivInfoPtr, A0 ; get ptr to ProductInfo Add.l ProductInfo.DecoderInfoPtr(A0), A0 ; point to the base address table Move.l DecoderInfo.PSCAddr(A0), PSCBase(A2) ; Save the PSC base address Move.l RecvRtn(A6), RcvRtn(A2) ; save addr of recv rtn Move.l RecvPrms(A6), RcvParm(A2) ; save parm for recv rtn Move.l XmitRtn(A6), XmtDnRtn(A2) ; save addr of xmit compl rtn Move.l XmitPrms(A6), XmtDnParm(A2) ; save parm for xmit compl rtn Move.l MACECfgPtr(A6), A4 Move.l MACECfg.MACEBase(A4), MACEBase(A2) Move.l A4, MCfg(A2) ; save ptr to MACE config record Move.l Dot3NetStats(A6), Dot3StatPtr(A2) Move.l LAPMIBNetStats(A6), LAPMIBStatPtr(A2) Move.l EnetAddr(A6), OurAddrPtr(A2) ; save ptr to our Ethernet address Move.l FastMoveRtn(A6), MemMove(A2) ; save addr of fast mem move rtn MoveQ #0, D0 ; initialize some regs Move.l D0, D2 Move.l D0, D3 Move.l D0, D5 Move MACECfg.XmitBuffs(A4), D2 Bne.s @10 Move #DefTxBuffs, D2 ; 0 passed in, set to default @10 Move MACECfg.RecvBuffs(A4), D3 Bne.s @11 Move #DefRxBuffs, D3 ; 0 passed in, set to default @11 Move MACECfg.RecvChains(A4), D5 Bne.s @12 Move #DefChns, D5 ; 0 passed in, set to default @12 ; force 1 ▓ recv chains ▓ max CmpI #OneChn, D5 ; 1 recv chain? Bne.s @chkmax ; no CmpI #MaxBufpChn, D3 ; too many buffers in our 1 chain? Bls.s @GetMem ; no Move #MaxBufpChn, D3 ; reset # of buffers to max allowed Bra.s @GetMem @chkmax CmpI #MaxChns, D5 ; must be ▓ max allowed Bls.s @cont1 Move #MaxChns, D5 @cont1 Move D5, MACECfg.RecvChains(A4) ; set # of chains Move D5, D0 ; D0.w=# of chains Move D3, D5 ; D5.l=# of recv buffers DivU D0, D5 ; D5.l=# of buffers per chain in low word Swap D5 ; get remainder in low word Tst D5 ; was there a remainder? Beq.s @noremndr ; no Sub D5, D3 ; adjust # recv buffers down so ; same # per chain Clr D5 ; clear remainder @noremndr Swap D5 ; get back # of buffers per chain CmpI #MaxBufpChn, D5 ; too many buffers per chain? Bls.s @chkmin ; no Move #MaxBufpChn, D5 ; reset # of buffers to max allowed Bra.s @cont2 @chkmin CmpI #MinBufpChn, D5 ; too few buffers per chain? Bhs.s @Getmem ; no Move #MinBufpChn, D5 ; reset # of buffers to min allowed Move #DefChns, MACECfg.RecvChains(A4) ; reset # of chains @cont2 Move D5, D3 ; D3=# of buffers per chain Move MACECfg.RecvChains(A4), D1 ; D1=# of chains MulU D1, D3 ; D3.l=total # of recv buffers @GetMem Move D2, D4 ; D4=# xmit buffers Move #XmitBuff.TxBuffSz, D0 MulU D4, D0 ; D0.l=memory for xmit buffers Move D3, D4 ; D4=# recv buffers Move #RecvBuff.RxBuffSz, D1 ; size of a recv buffer MulU D1, D4 ; D4.l=memory for recv buffers, used later Add.l D4, D0 ; D0=memory for recv & xmit buffers AddI.l #RecvBuff.RxBuffSz, D0 ; add 1 since we must 2K align recv buffs WITH GetMem Sub.l #GetMemSz, SP ; room for results Move.l D0, memsize(SP) ; requested memory size Move.l #(1< next buffer address Move.l A1, Next(A0) ; set link to next buffer MoveA.l A1, A0 ; point to next buffer @x1 DBra D0,@x2 ; do them all Clr.l Next(A0) ; clear last buffer's next ptr ; ; Get and save physical address of each transmit buffer's packet data area ; This loop depends on all buffers being contiguous. ; Move.l FreeXmtBuff(A2), A0 ; Get Xmit header pointer Move.l D2,D1 SubQ #1,D1 ; adjust loop count @x3 Lea Packet(A0), A1 ; Get Packet logical address MoveM.l A0/D1/D2, -(SP) ; Save used C regs Move.l #TxBuffSz, -(SP) ; logical size Move.l A1, -(SP) ; logical address Lea TranslateAddress, A0 Jsr (A0) ; get physical address in D0 MoveA.l (SP)+, A1 ; get back buffer addr AddQ #4, SP ; trash length MoveM.l (SP)+, A0/D1/D2 ; restore used C regs Blt @InitError Move.l A1, LogBufPtr(A0) ; save logical address Move.l D0, PhyBufPtr(A0) ; save physical address Lea TxBuffSz(A0), A0 ; A0-> next buffer address DBra D1,@x3 ; do them all ENDWITH ; ; MACE Chip initialization ; MoveA.l MACEBase(A2), A0 ; A0-> base address of Mace regs Bsr ResetMACE ; Reset MACE chip and PSC DMA chnls Move.b #(1< Default: ; Enable Retry, FCS, Auto Padding Move.b MACECfg.RecvFrmCtl(A4), MACE_RX_FRM_CNTRL(A0) ; Recv Control -> Default: ; Disable Auto Pad Stripping ; Set up FIFOs' configuration Move.b MACECfg.FIFOCfgCtl(A4), MACE_FIFO_CNFG(A0) Move.b #0, MACE_PLS_CNFG(A0) ; Set up for normal transmit Move.b MACE_CHIP_ID_HIGH(A0), D0 Lsl #8, D0 Move.b MACE_CHIP_ID_LOW(A0), D0 Move D0, MACEChipID(A2) Move.b #(1< Mace Phy Address Reg MoveA.l OurAddrPtr(A2), A1 ; A1-> Our node address Move.b (A1)+, (A0) ; Move addr byte0 to Mace reg Move.b (A1)+, (A0) ; Move addr byte1 to Mace reg Move.b (A1)+, (A0) ; Move addr byte2 to Mace reg Move.b (A1)+, (A0) ; Move addr byte3 to Mace reg Move.b (A1)+, (A0) ; Move addr byte4 to Mace reg Move.b (A1), (A0) ; Move addr byte5 to Mace reg MoveA.l MACEBase(A2), A0 ; Get back base address of Mace regs Move.b #(1< Mace Phy Address Reg MoveQ #7, D0 @laf Move.b #0, (A1) ; CLEAR all bits in Log Addr Filter DBra D0, @laf Move #0, NxtXmitSet(A2) ; make set0 next reg set to xmit on Move #0, ActXmitSet(A2) ; make set0 active xmit reg set Move #0, ActRecvSet(A2) ; make set0 active recv reg set IF SETDEBUG THEN ;???? temp code to see if we have post evt5 PSC that has non-sticking register write fix MoveA.l VIA, A1 BTst #vSCCWrReq, vDirA(A1) ; new psc: bit(vSCCWrReq) = 0 ; old psc: bit(vSCCWrReq) = 1 Seq.b hasNewPSC(A2) ; end temp code ENDIF Bsr InitRecvChl ; Initialize DMA recv channel ; Install MACE Recv DMA channel Deferred Task, called by MACE_RECVhndlr Move.w #dtQType, DTQE+qType(A2) ; Set Deferred Task queue type Lea MaceRecv, A1 Move.l A1, DTQE+dtAddr(A2) ; Set address of DT, called by slot int. hndlr. Move.l A2, DTQE+dtParm(A2) ; Set variable pointer to MACE vars ; Install PSC DMA handlers for Mace Recv & Xmit channels MoveA.l PSCBase(A2), A3 ; Get the PSC base address WITH ExpandMemRec MoveA.l ([ExpandMem],emDMADispatchGlobals), A0; A0-> PSC Interrupt table ptr ENDWITH Lea PSCInterrupt, A1 Move.l A1, MACE_RECVhndlr(A0) ; Install DMA recv handler Move.l A2, MACE_RECVparm(A0) ; MaceVarPtr passed back in A1 Move.l A1, MACE_XMIThndlr(A0) ; Install DMA xmit done handler Move.l A2, MACE_XMITparm(A0) ; MaceVarPtr passed back in A1 Move.b #(1<