; ; File: PDMMace.a ; ; Contains: routines to support MACE when coupled with a AMIC-style DMA model ; ; Written by: Sean Findley, Mark A. Law, Gary Rensberger ; ; Copyright: © 1990-1993 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 10/6/93 RC Took out PDM EVT1 support ; 9/20/93 GMR Fixed a bug where we might count a xmit frame twice, if we got ; an underflow interrupt in the middle of transmission. ; 9/9/93 pdw Changed installation of MACE int to maceVector in ; DMADispatchGlobals instead of ddMACE…. ; 9/2/93 chp Change MaceVarPtr from DC.L 1 to DC.L 0 so that the MACE ; variables are initialized to “none.” ; 8/30/93 chp InterruptHandlers.a now supports MACE interrupts on PDM. ; Modified the MACEInterrupt exception handler to run as a ; subroutine to the system interrupt dispatcher, so deferred tasks ; can now run following a MACE interrupt. Modified MACE and Enet ; DMA interrupt routines to save and restore only those registers ; not saved by the interrupt dispatcher. Modified the install code ; to install interrupt handlers into the AMIC dispatch table ; rather than AutoInt3, and to do so directly rather than calling ; _DMAIntInstall. ; 8/20/93 GMR Added AMIC4 support (don't apply AMIC headPtr hack if on AMIC4). ; 8/4/93 GMR Fixed a bug that caused the xmit routine to count a packet as ; going out, but which didn't go out because of a bad length. ; 7/1/93 GMR Backed out a couple of the changes in which were ; unnecessary; the branch to the wrong label was the only change ; needed to fix the problem. ; 7/1/93 pdw Fixed the "Blowed up after Macsbug" bug which was due to not ; handling MACE Overflow problems correctly which were due to AMIC ; overflows caused by the deferred task processing of packets ; which was not happening because Macsbug turns off the Deferred ; Task Manager which was... It was late one night... Actually we ; just moved the @done label up one line. ; 6/28/93 GMR Made receive handling use deferred tasks now, instead of ; processing at level 4. ; 6/10/93 GMR Fixed a couple bugs (found by test tool) in the level 3 Mace ; handler, and in handling transmit completions. ; 6/8/93 GMR Added support for EVT1. Temporarily fixed privilage violation ; when running VM; the level 3 handler installation really needs ; support from Inthandlers.a. ; 6/3/93 GMR Remove debugger on receive overflow. ; 6/2/93 GMR Now, defer transmits until we get a MACE interrupt indicating ; the previous packet went out. ; 6/2/93 GMR Rewrote the interrupt handlers and cleaned up parts of the code. ; 6/1/93 dwc Fix init code, add code to wait for MACE transmit status valid ; to work around MACE's not returning it in a timely manner. ; 5/27/93 dwc Added work-around code to wait for AMIC to finish writing a ; packet into the receive DMA buffer before handling it. ; 5/25/93 dwc Cleaned uo for Alpha. Removed some more debug code and hardware ; patches. Added simple work around for AMICs' incrementing the ; head pointer before it has finished writing the packet into the ; DMA buffer. This is a kluge, but it is the fastest one I ; tried, and throws away the fewest packets. ; 5/4/93 dwc Added debug code to work around AMIC's returning FF's on the ; first read. Added test for EVT1/EVT2. ; 4/6/93 dwc Updated for level #4 DMA interrupts. ; 3/24/93 dwc Remove obsolete code and added code to try to recover from ; lowered interrupt level during packet handling. ; 3/5/93 dwc Removed some more debugging and obsolete code and comments. ; 2/25/93 dwc Enabled receive, removed some debug code and obsolete routines. ; 2/24/93 dwc Cleaned up transmit, disabled receive for PDM D5 ROM build. ; 11/30/92 dwc Moved INTLockOut, DMALockOut to PDMMaceEqu.a. ; 11/20/92 dwc Convert to PDM. ; ; To Do: Look into AMIC not properly detecting receive overflow (head continues to wrap past ; the tail without error). ; ; Notes: This version supports EVT2 and later machines. ; ; 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 BUFDEBUG EQU 0 DEBUG EQU 0 PROM EQU 0 Logging EQU 1 SUPPORTS_OLD_HW EQU 1 USEDEFERREDTASK EQU 1 PRINT NOGEN,NOMDIR,ON INCLUDE 'PDMMaceEqu.a' ; Mace definitions INCLUDE 'AMICEqu.a' ; AMIC 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 AMIC DMA interrupts NeedDefer EQU 5 ; bit indicates VM is running MACERevA2 EQU $0941 MACERevB0 EQU $0940 MAX_STAT_PEND EQU 1 MaceVars RECORD 0 ; our variables MACEmem DS.l 1 ; ptr to memory block with recv & xmit buffers MACEmemSz DS.l 1 ; need size if need to free it XmitBuffMem DS.l 1 ; xmit buffer mem DMAPacketPtr DS.l 1 ; ptr to active receive packet in DMA buffer MACEBase DS.l 1 ; MACE base address AMICDMABase DS.l 1 ; AMIC DMA base address DTQE DS.b dtQElSize ; Deferred task queue element 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 DeferFlag ds.b 1 ; bit 0 = deferred task installed. XmitPend ds.b 1 ; <> 0 = # xmits pending XmitStat ds.b 1 ; <> 0 = # xmit status's pending from mace IF SUPPORTS_OLD_HW THEN BoardFlag ds.b 1 ; 00 = AMIC1-3 ; 01 = AMIC4 ENDIF ALIGN 4 DMABufStart DS.l 1 ; logical addr of start of DMA recv buffer TxBuffPtr0 DS.l 1 ; logical addr of start of DMA xmit buffer0 TxBuffPtr1 DS.l 1 ; logical addr of start of DMA xmit buffer1 XmitRegSet ds.w 1 ; 0 or 1 ByteCount ds.w 1 ; bytes in current xmit packet 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) 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 RcvBuffer ds.b 6*256 ; Receive buffer (transfered to from DMA buffer) IF Logging THEN LogPtr ds.l 1 LogEndPtr ds.l 1 ; ptr to end of log LogStart ds.l 512*4 ; room for 512 log entries LogEnd ENDIF MaceVarSz EQU * ; End of variables ENDR ;----------------------------------------------------------------- ; Receive Buffer template ; -ensure 1st one is quad-aligned and all the rest will be ;----------------------------------------------------------------- RecvBuff Record 0 MaceStat DS.b 4 ; Recv'd pkt status from Mace DS.b 4 ; Garbage bytes Packet DS.b Max_Pkt_Size ; packet data area EndR EJECT STRING PASCAL MACHINE MC68020 MaceData PROC ENTRY MaceVarPtr MaceVarPtr DC.L 0 ; Contains ptr to my variables ENDP ;________________________________________________________________________ ; ; ResetMACE - Reset AMIC & 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 ; reset & disable MACE -> AMIC receive path MoveA.l MACEBase(A2), A0 ; A0-> base address of MACE regs MoveA.l AMICDMABase(A2), A1 ; A1-> base address of AMIC regs Move.b #0, MACE_MAC_CNFG(A0) ; Disable MACE recv, xmit, et. al. nop Move.b MACE_FIFO_CNFG(A0), D0 ; Get current FIFO config OrI.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 AMIC recv FIFO, and reprime affected DMA Reg. Set. Finally, ; update the LAF. ;________________________________________________________________________ WriteLAF PROC WITH MACERegs,MaceVars 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 AND write completion (interrupt level 4) ;___________________________________________________________________________ PrimeXmitRS PROC IMPORT AddToLog XmitPrm RECORD 4 XmitPtr DS.l 1 ; Transmit buffer ptr ParmSz EQU * ENDR WITH MACERegs,MaceVars,LAPMIBStats addq.b #1,XmitStat(a2) ; count this packet as waiting to go out move.l AMICDMABase(A2),A3 ; Get AMIC DMA base addr Move.b AMIC_DMA_XMIT_CNTL(A3), D1 ; get xmit status BTst #DMARUN, D1 ; DMA enabled already? Beq @noten ; No, don't reset it move.b #XMTMSK, AMIC_DMA_XMIT_CNTL(A3) ; Clear IF & DMARUN nop @noten moveq #0, D0 Move.w ByteCount(A2), D0 ; Get DMA byte count (word) move.w XmitRegSet(a2),d1 ; get register set lsl #4,d1 ; * 16 for proper reg offset IF Logging THEN move.l #'DMA ',-(sp) move.l #'SEND',-(sp) move.l d0,-(sp) move.w XmitPend(a2),(sp) bsr AddToLog add.w #12,sp ENDIF Move.b D0, (AMIC_DMA_XMIT_CNT0L,A3,d1.w) ; Set DMA byte count (LOW) nop ; Allow it to complete ror.w #8,D0 ; Get HIGH count into lower byte Move.b D0, (AMIC_DMA_XMIT_CNT0H,A3,d1.w) ; Set DMA byte count (HIGH) nop ; Allow it to complete @aroundone rol.w #8,D0 ; Get HIGH count back into upper byte Move.l XmitPrm.XmitPtr(SP),a1 ; a1 - xmit buffer ptr 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.b #XMTDMA, AMIC_DMA_XMIT_CNTL(A3) ; Clear IF & enable xmit DMA nop ; Allow it to complete MoveQ #0, D0 ; Set CC's Rts ; Return 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). Due to ; a hardware problem in Curio (it seems), you cannot DMA another packet into ; MACE before a pending Xmit status is read, or the transmitter locks up. Hence ; the code below will return a 'nobuff' error if there is an outstanding status. ; If the part is fixed, then by modifying a constant, the code will allow 2 or more ; packets to go out before returning the error. ;___________________________________________________________________________ MaceXmit PROC EXPORT WDSPrm RECORD 4 ; Return address WDSPtr DS.l 1 ; Write Data Structure ptr ParmSz EQU * ENDR IMPORT AddToLog WITH MACERegs,MaceVars Move.l WDSPrm.WDSPtr(SP), D2 ; Get WDS ptr movem.l A0-A4/D1-D4,-(SP) ; save non-scratch 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 AMICDMABase(A2),a0 ; Get AMIC DMA base addr Move.b AMIC_DMA_XMIT_CNTL(A0),d0 ; Which reg set is available? andi.b #(1< 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,ByteCount(A2) ; sum the length Bra.s @1 ; look for more @2 Move.w ByteCount(A2),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)+,A1 ; ••Pop buff ptr Move (SP)+,sr ; ••Restore int. mask level Movem.l (SP)+,A0-A4/D1-D4 ; Restore C regs MoveQ #eLenErr,D0 ; Set length error Rts ; Return it ;------------------------------------------ ; Copy WDS data to our Xmit buffer ;------------------------------------------ @cont MoveA.l (SP),A1 ; 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 ; (SP) -> Xmit buffer ptr pushed earlier Jsr PrimeXmitRS AddQ #4,sp ; ••Pop buff ptr Move (SP)+,SR ; ••Restore int. mask level Movem.l (SP)+,A0-A4/D1-D4 ; Restore C regs MoveQ #0, D0 ; Set return code & CC's Rts ; Return ENDP EJECT ;___________________________________________________________________________ ; ; MaceRecv - Deferred Task Packet receive routine ; ; Call: a1 - our variables ; ; Return: ; ; Destroys: a0-a1,d0-d1 ; ; Calls: ; Calls user's handler to receive packet. ; ; Notes: ; Installed via DMAInterrupt, called via Deferred Task Mgr. ;___________________________________________________________________________ MaceRecv PROC IMPORT AddToLog,CopyRcvBuffer,InitStatBuf WITH MACERegs,MaceVars,RecvBuff WITH Dot3StatsEntry,LAPMIBStats movem.l A2-A6/D2-D4,-(SP) ; save non-scratch regs move.l a1,a2 ; get ptr to our globals @ChkRecv movea.l AMICDMABase(a2),a3 ; get ptr to AMIC move.w sr,-(sp) ; •• save sr ori.w #DMALockOut,sr ; • mask out DMA ints ;-------------------------------------- ; Here we check for a valid packet in the circular buffer... ;-------------------------------------- @rcvPcktLoop moveq #0,d0 move.b AMIC_DMA_RECV_TAIL(A3),D0 ; Are there packets to process? (should be) cmp.b AMIC_DMA_RECV_HEAD(A3),D0 ; Get the Head Ptr bne @gotData btst.b #6,AMIC_DMA_RECV_CNTL(a3) ; overrun? beq @exit IF Logging THEN move.b AMIC_DMA_RECV_HEAD(A3),d0 move.l #'McRv',-(sp) ; push string move.l #'OVER',-(sp) ; push string move.l #'RUN ',-(sp) ; push string bsr AddToLog add.w #12,sp ENDIF @gotData tst.l DMAPacketPtr(a2) ; did we re-enter?? bne @exit ; yes, exit for now IF Logging THEN move.l d0,-(sp) swap d0 move.b AMIC_DMA_RECV_HEAD(A3),d0 move.l #'DMAr',-(sp) ; push string move.l d0,-(sp) ; push tail/head move.l DMABufStart(A2),a0 ; Recv buffer ptr clr.w d0 swap d0 lsl.w #8,d0 adda.l d0,a0 ; point to start of packet move.l (a0),-(sp) ; push status/length bsr AddToLog add.w #12,sp move.l (sp)+,d0 ENDIF move.l DMABufStart(A2),a0 ; Recv buffer ptr lsl.w #8,d0 ; convert to offset add.l d0,a0 ; a0=addr of packet IF SUPPORTS_OLD_HW THEN tst.b BoardFlag(a2) ; AMIC4? bgt.s @skipStat ; yes, don't bother with the hack tst.l (a0) ; • has status been updated? beq @exit ; • no, not full packet, exit @skipStat ENDIF move.l a0,DMAPacketPtr(a2) ; save ptr, flag we're in use move.w (sp)+,sr ; •• restore interrupts ;-------------------------------------- ; we seem to have a complete packet, get it's status, ; copy DMA buffer to our receive buffer (if status valid), ; and call user with data ;-------------------------------------- moveq #0,d1 move.w (a0),d1 ; Get Status(15-12) & Byte Cnt(11-8,7-0) move.w d1,d2 ; want Status later lsr.w #8,d2 ; d2.w=00ss andi.b #$f0,d2 ; d2.w=00s0 swap d2 ; d2.l=s000 move.w 2(a0),d2 ; d2.l=s0cr (Get the Collision & Runt cnts) swap d2 ; d2.l=crs0 (Coll,Runt,Stat,Null) andi.w #$0fff,d1 ; remove status bits from byte cnt bsr CopyRcvBuffer ; copy the DMA buffer into our receive buffer btst.b #6,AMIC_DMA_RECV_CNTL(a3) ; are we in an overrun condition? beq.s @notOverrun IF Logging THEN move.b AMIC_DMA_RECV_HEAD(A3),d0 move.l #'McR2',-(sp) ; push string move.l #'OVER',-(sp) ; push string move.l #'RUN ',-(sp) ; push string bsr AddToLog add.w #12,sp ENDIF move.b #$4a,AMIC_DMA_RECV_CNTL(a3) ; yes, clear the overrun and turn on DMA @notOverrun 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. ;----------------------------------------------------------------- Add.l d1,ifInOctets(a5) Btst #RcvOFLO,d2 ; Overflow Error? Beq.s @s1 AddQ.l #1,dot3StatsInternalMacReceiveErrors(a6) Bra.s @s4 ; @s1 AndI.b #(1< beq.s @skipCnt ; no, don't count it subq.b #1,XmitStat(a1) ; else, count this frame status as read @skipCnt IF Logging THEN move.l #'MACE',-(sp) move.l d0,-(sp) ; log interrupt reg move.b d1,1(sp) ; and frame status move.l XmitPend(a1),-(sp) move.b MACE_FIFO_FRM_CNT(A0),2(sp) ; and frame counts bsr AddToLog add.w #12,sp ENDIF BTst #XMTSV, D1 ; Is status valid? Bne.s @10 ; yes, continue AddQ.l #1, XmtStatINV(A1) Bra @xmit @10 Move.b D1, -(SP) ; save D1 AndI.b #(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? Beq.s @chkAgain ; no AddQ.l #1, dot3StatsFrameTooLongs(A3) AddQ.l #1, ifOutErrors(A2) @chkAgain bra @more ENDP ;___________________________________________________________________________ ; ; Routine: CopyRcvBuffer ; ; Inputs: d1 - packet length ; d2 - packet status ; a0 - ptr to start of packet in DMA buffer ; a2 - globals ; a2 - AMIC base ; Outputs: RcvBuffer - contains the received packet ; Destroys: a1,d3 ; ; Calls: ; ; Function: Copyies the packet in DMA buffer to our receive buffer, bumping ; the tail pointer as we go. ;___________________________________________________________________________ CopyRcvBuffer PROC EXPORT WITH MACERegs,MaceVars move.l d1,-(sp) ; save length tst.b d2 ; check status, is length valid? bne.s @copyExit add.w #$00ff+8,d1 ; compute the rounded up length in pages andi.w #$ff00,d1 lsr.w #8,d1 ; # of pages (256 bytes) subq.w #1,d1 ; adjust for dbra blt.s @copyExit moveq #0,d3 move.b AMIC_DMA_RECV_TAIL(a3),d3 ; get tail ptr move.l DMAPacketPtr(a2),a0 ; get buf ptr lea RcvBuffer(a2),a1 ; get ptr to our receive buffer @clrLoop move.l #$0100,d0 _BlockMove ; copy next page to user buffer add.w #$0100,a1 ; point to next page clr.l (a0) ; clear out it's length/status ••hardware fix add.w #$0100,a0 ; point to next status addq.b #1,d3 ; bump tail ptr cmpi.b #$c0,d3 ; at end of buffer? blo.s @update ; no, continue moveq #0,d3 ; yes, reset to starting page move.l DMABufStart(a2),a0 ; wrap length/status ptr to start @update move.b d3,AMIC_DMA_RECV_TAIL(a3) ; update tail ptr nop cmp.b AMIC_DMA_RECV_HEAD(a3),d3 ; have we caught up with head (bad length)? dbeq d1,@clrLoop ; and repeat for next page @copyExit move.l (sp)+,d1 rts ENDP EJECT ;___________________________________________________________________________ ; ; DMAIntHandler - Process DMA Interrupt from AMIC ; ; Call: A1 - our variables (reference constant from dispatcher) ; ; Regs: 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. ;___________________________________________________________________________ DMAIntHandler PROC IMPORT AddToLog,InitStatBuf,CopyRcvBuffer WITH MACERegs,MaceVars Move.l D4, -(SP) ; Save non-interrupt regs used Move.l A1,A2 ; A2 -> our variables ;-------------------------------------- ; Check for packet in Receive DMA Channel ;-------------------------------------- ChkRecv MoveA.l AMICDMABase(a2),a3 Move.b AMIC_DMA_RECV_CNTL(a3),d0 ; Get receive status, int pending? bpl @ChkXmitDone ; no, check xmit channel btst #6,d0 ; is this an overrun? beq.s @notOVRN ; no, continue IF Logging THEN move.b AMIC_DMA_RECV_HEAD(A3),d0 move.l #'RECV',-(sp) ; push string move.l #'OVER',-(sp) ; push string move.l #'RUN ',-(sp) ; push string bsr AddToLog add.w #12,sp ENDIF IF DEBUG THEN _debugger ENDIF Move.b #$80, AMIC_DMA_RECV_CNTL(A3) ; Clear the interrupt bra.s @2 @notOVRN Move.b #RCVMSK, AMIC_DMA_RECV_CNTL(A3) ; Clear the interrupt and turn on DMA @2 nop IF Logging THEN move.b AMIC_DMA_RECV_HEAD(A3),d0 move.l #'DMAr',-(sp) ; push string move.l #'Int ',-(sp) ; push string move.l DeferFlag(a2),-(sp) bsr AddToLog add.w #12,sp ENDIF bset #0,DeferFlag(a2) ; we're installing deferred task bne.s @ChkXmitDone ; skip if already installed IF USEDEFERREDTASK THEN lea DTQE(a2),a0 ; A0->deferred task queue element movea.l JDTInstall,a1 jsr (a1) ; install deferred task ELSE move.l a2,a1 ; a1 = globals for deferred tasks bsr MaceRecv ENDIF ;--------------------------------------------------------------- ; Check for Transmit Completion Interrupt ;--------------------------------------------------------------- @ChkXmitDone move.b AMIC_DMA_XMIT_CNTL(a3),d0 ; AMIC xmit control/status bpl @doneAMICInt ; exit if no xmit DMA int IF Logging THEN move.l #'DMA ',-(sp) move.l #'DONE',-(sp) move.l d0,-(sp) bsr AddToLog add.w #12,sp ENDIF Move.b #XMTMSK, AMIC_DMA_XMIT_CNTL(A3) ; clear the interrupt nop @doneAMICInt Move.l (SP)+, D4 rts ; Return from DMAInterrupt ENDP EJECT ;___________________________________________________________________________ ; ; MaceInit - Get var and DMA memory, then initialize DMA Register Sets and ; MACE chip ; ; Call: following record on stack: ; ; MACEInitParms RECORD 0 ; RecvRtn DS.l 1 ; address of Ethernet receive routine ; RecvPrms DS.l 1 ; parms to pass @ receive ; XmitRtn DS.l 1 ; address of Ethernet xmit complete routine ; XmitPrms DS.l 1 ; parms to pass @ xmit complete ; MACECfgPtr DS.l 1 ; ptr to MACE config record ; Dot3NetStats DS.l 1 ; ptr to 802.3 statistics array ; LAPMIBNetStats DS.l 1 ; ptr to LAP MIB statistics array ; EnetAddr DS.l 1 ; ptr to ethernet address ; FastMoveRtn DS.l 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, AddToLog, InitStatBuf WITH parms,initp,MACERegs,MaceVars Link A6,#LocalSize ; Save A6 MoveM.l A2-A4/D3-D5,-(SP) ; Save regs Move.l #MaceVarSz, -(SP) ; requested memory size Move #0, -(SP) ; do NOT want memory locked, ; contiguous, and non-cacheable Lea GetMemory, A0 Jsr (A0) ; get memory in D0 AddQ #6, SP ; pop parms Blt @InitError ; bra if CC indicate error Lea MaceVarPtr, A3 Move.l A0, (A3) ; Save ptr to my vars MoveA.l A0, A2 IF SUPPORTS_OLD_HW THEN clr.b BoardFlag(a2) ; init to AMIC1-3 move.w sr,-(sp) ;•• ori.w #$0700,sr ; mask ints during this lea $50f14010,a0 move.b (a0),d1 move.b d1,-(sp) ;•• read AMIC, save old value btst.l #3,d1 ; check bit 3 bne.s @amic4 ; if set, must be amic4 ori.b #(1<<3),d1 ; clear, get set mask move.b d1,(a0) ; try setting bit 3 nop btst.b #3,(a0) ; did it set? beq.s @hwChkDone ; no, must be AMIC1-3 @amic4 addq.b #1,BoardFlag(a2) ; yes, 01=AMIC4 @hwChkDone move.b (sp)+,(a0) ; •• restore AMIC move.w (sp)+,sr ; •• restore SR ENDIF IF Logging THEN lea LogStart(a2),a0 move.l a0,LogPtr(a2) lea LogEnd(a2),a0 move.l a0,LogEndPtr(a2) move.l #'STRT',-(sp) move.l #'ENET',-(sp) clr.l -(sp) bsr AddToLog add.w #12,sp ENDIF Move.l UnivInfoPtr, A0 ; get ptr to ProductInfo Add.l ProductInfo.DecoderInfoPtr(A0), A0 ; point to the base address table Move.l DecoderInfo.MACEAddr(A0), MACEBase(A2) ; Save the MACE base address Move.l DecoderInfo.AMICAddr(A0), AMICDMABase(A2) ; Save the AMIC 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 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 ;------------------------------------------------------------------------------------- ; Get the buffer addresses from the AMIC base address register + offsets ;------------------------------------------------------------------------------------- lea $61000000,a1 ; Get the buffer base address Move.l a1,DMABufStart(A2) ; Set Recv buffer pointer adda.l #XMIT_BUFF0,a1 ; D0 = Recv ptr + xmit buff offset Move.l a1,TxBuffPtr0(A2) ; Set 1st Xmit buffer pointer adda.w #2048,a1 Move.l a1,TxBuffPtr1(A2) ; Set 2nd Xmit buffer pointer IF SUPPORTS_OLD_HW THEN tst.b BoardFlag(a2) ; AMIC4? bgt.s @skipStat ; yes, don't bother with the hack bsr InitStatBuf ; •• hack to init status words at each page boundary @skipStat ENDIF ;------------------------------------------------------------------------------------- ; 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 ;------------------------------------------------------------------------------------- ; MACE Chip initialization ;------------------------------------------------------------------------------------- MoveA.l MACEBase(A2), A0 ; A0-> base address of Mace regs Bsr ResetMACE ; Reset MACE chip and AMIC DMA chnls Move.b #(1< ; Enable Retry, FCS, Auto Padding Move.b #$00, MACE_RX_FRM_CNTRL(A0) ; •••Recv Control -> ; Disable Auto Pad Stripping ; Set up FIFOs' configuration Move.b #TFW16+(1< Mace Phy Address Reg MoveA.l OurAddrPtr(A2), A1 ; A1-> Our node address Move.b (A1)+, (A0) ; Move addr byte0 to Mace reg nop ; Allow it to complete Move.b (A1)+, (A0) ; Move addr byte1 to Mace reg nop ; Allow it to complete Move.b (A1)+, (A0) ; Move addr byte2 to Mace reg nop ; Allow it to complete Move.b (A1)+, (A0) ; Move addr byte3 to Mace reg nop ; Allow it to complete Move.b (A1)+, (A0) ; Move addr byte4 to Mace reg nop ; Allow it to complete Move.b (A1), (A0) ; Move addr byte5 to Mace reg nop ; Allow it to complete MoveA.l MACEBase(A2), A0 ; Get back base address of Mace regs CmpI #MACERevA2, MACEChipID(A2) ;???? temp code to check MACE chip id Beq.s @skip2 ; MACE in Rev B0 Curio has new bit in IAC! Move.b #(1< Mace Phy Address Reg MoveQ #7, D0 @laf Move.b #0, (A1) ; CLEAR all bits in Log Addr Filter nop ; Allow it to complete DBra D0, @laf MoveA.l AMICDMABase(A2), A3 ; Get the AMIC base address Move.b #(1<Get the AMIC base address Move.b #XMTMSK, AMIC_DMA_XMIT_CNTL(A3) ; Clear IF to be safe nop ; Allow it to complete Move.b #RCVMSK, AMIC_DMA_RECV_CNTL(A3) ; Clear IF & enable recv DMA nop ; Allow it to complete ; Be sure the Tail Pointer starts out a 0 Move.b #0, AMIC_DMA_RECV_TAIL(A3) ; Start at the beginning nop ; Allow it to complete ;------------------------------------------------------------ ; Install Enet interrupt handlers ;------------------------------------------------------------ with ExpandMemRec, DMADispGlobals movea.l ([ExpandMem],emDMADispatchGlobals), A0 ; Install MACE (level 3) interrupt handler lea MaceInterrupt, A1 move.l A1, maceVector(A0) ; register the handler in its designated entry ; Install AMIC DMA (level 4) interrupt handlers lea DMAIntHandler, A1 moveq #hwAmicETX, D0 move.l A1, ddVector0(A0,D0.l*8) ; register transmit DMA handler move.l A2, ddRefCon0(A0,D0.l*8) ; register globals pointer as reference constant moveq #hwAmicERX, D0 move.l A1, ddVector0(A0,D0.l*8) ; register receive DMA handler move.l A2, ddRefCon0(A0,D0.l*8) ; register globals pointer as reference constant endwith ;------------------------------------------------------------ ; Enable MACE ;------------------------------------------------------------ Move.l MACEBase(A2), A0 ; Base address of Mace Move.b #(1<