sys7.1-doc-wip/DeclData/DeclNet/Mace/Mace.a
2019-07-27 22:37:48 +08:00

2730 lines
88 KiB
Plaintext

;
; 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):
;
; <SM10> 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().
; <SM9> 6/14/93 kc Roll in Ludwig.
; <LW9> 5/14/93 mal #1084946 Fixed race between xmit interrupt and non-interrupt
; rtns. that could result in sending out-of-order packets.
; <LW8> 5/3/93 mal #1082628 Fixed race between deferred task and int. hndlr. rtns.
; See MaceRecv:@exit for details.
; <LW7> 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.
; <LW6> 3/21/93 mal Fix last checkin bug in WriteLAF where MACE_MAC_CONFIG must be
; saved.
; <LW5> 3/21/93 mal Remove Curio A2 support, ie. evt3 support. Removed use of
; _SetIntMask. Write-once on bug-fixed PSC.
; <LW4> 3/16/93 chp Replace references to the obsolete PSCIntTbl lomem with
; references to the equivalent field in ExpandMem.
; <LW3> 2/17/93 mal Moved receive chain/buffer headers out of unused portion of DMA
; buffer and into separate memory block.
; <LW2> 1/27/93 mal Added MACEecfg rsrc support. Changed promiscuous mode support to
; lower main codepath risk.
; <SM8> 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.
; <SM7> 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
; <SM6> 11/10/92 mal Fixed bug in Mace open that could corrupt memory byte off A3;
; Corrected reporting of Recv FIFO overflow to
; InternalMacRecvError.
; <SM5> 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.
; <SM4> 10/26/92 mal Updated to ESD's latest stats equs.
; <SM3> 10/26/92 mal Fixed some bugs and modified recv/xmit buffer memory allocation
; loop in open().
; <SM2> 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.
; <SM6> 9/14/92 mal -Updated SNMP counters; -added temp code to handle all Curio
; revs up to B0
; <SM5> 7/27/92 mal Added temp code to handle version 1 'ebfr's.
; <SM4> 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.
; <SM3> 6/26/92 mal Expanded # of maceinit parms saved in globals.
; <SM2> 6/22/92 mal New drvr to support PSC2's (EVT2) Ethernet DMA receive model.
; <SM1> 5/21/92 RB Removed the inclusion of VMCalls.a, got rid of a warning
; branch to next instruction and included InternalOnlyEqu.a
; <P3> 5/5/92 mal Removed some unused global vars
; <P2> 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<<SENSE)+(1<<SWRESET), PSC_MACE_XMIT_CNTL(A0)
MoveA.l MACEBase(A2), A1
Move.b MACE_MAC_CNFG(A1), D0 ; get current MACE mac config
Move.b D0, -(SP) ; save it
BClr #ENXMT, D0
Move.b D0, MACE_MAC_CNFG(A1) ; Disable xmit
Move.b MACE_FIFO_CNFG(A1), D0 ; Get current MACE FIFO config
OrI.b #(1<<XMTFWR), D0
Move.b D0, MACE_FIFO_CNFG(A1) ; Reset MACE xmit FIFO
Bsr.s RecoverXmitBuffs
Move #0, ActXmitSet(A2) ; reset offset to active xmit reg set
Move #0, NxtXmitSet(A2) ; reset offset to next reg set to xmit on
MoveA.l PSCBase(A2), A0
Move #(1<<PAUSE), PSC_MACE_XMIT_CNTL(A0) ; UnPause the DMA xmit channel
Move.b (SP)+, D0 ; get previous config
MoveA.l MACEBase(A2), A0
Move.b D0, MACE_MAC_CNFG(A0) ; restore config
Rts
ENDP
EJECT
;________________________________________________________________________
;
; Initialize A SINGLE Recv DMA Channel Register Set
; Call:
; A1 - Receive Buffer Descriptor address
; A2 - globals
; A3 - DMA recv chnl base
; D4 - offset to reg set
; Return: none
;________________________________________________________________________
InitRecv PROC
WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr
Move #(1<<IF), CmdStat(A3,D4) ; Clear interrupt
Move.l A1, RxChainSet0(A2,D4) ; Save addr of recv chain descriptor
IF SETDEBUG THEN
IF not SETDEBUGFAIL THEN
Tst.b hasNewPSC(A2)
Beq.s @a01 ; go to old PSC patch
Move.l PhyChnPtr(A1), Addr(A3,D4) ; Set DMA dest addr to phys addr of chain
Bra.s @aaa1
@a01
ENDIF
Move.l PhyChnPtr(A1), D0
And.l #$FFFFF000, D0 ; 2K aligned addr
@a1 Move.l PhyChnPtr(A1), Addr(A3,D4) ; Set DMA dest addr to phys addr of chain
Move.l Addr(A3,D4), D1
And.l #$FFFFF000, D1 ; 2K 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 PhyChnPtr(A1), Addr(A3,D4) ; Set DMA dest addr to phys addr of chain
ENDIF
MoveQ #0, D0 ; init D0
Move savedLimit(A1), Limit(A1)
Move Limit(A1), D0
IF SETDEBUG THEN
IF not SETDEBUGFAIL THEN
Tst.b hasNewPSC(A2)
Beq.s @a02 ; go to old PSC patch
Move.l D0, Cnt(A3,D4) ; Set DMA count to # of segments in chain
Bra.s @aaa2
@a02
ENDIF
@a2 Move.l D0, Cnt(A3,D4) ; Set DMA count to # of segments in chain
Move.l Cnt(A3,D4), 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(A3,D4) ; Set DMA count to # of segments in chain
ENDIF
Move #0, Out(A1) ; Initialize Out
IF BUFDEBUG THEN
Move #0, In(A1) ; Initialize In
ENDIF
Move.b #(1<<OnOffSet), State(A1) ; Set chain's state to ON reg set and
; clear flush indication
IF SETCSDEBUG THEN
IF not SETCSDEBUGFAIL THEN
Tst.b hasNewPSC(A2)
Beq.s @a03 ; go to old PSC patch
Move #(1<<SENSE)+(1<<IE)+(1<<ENABLED), CmdStat(A3,D4)
Bra.s @aaa3
@a03
ENDIF
@a3 Move #(1<<SENSE)+(1<<IE), CmdStat(A3,D4)
Move CmdStat(A3,D4), D0
BTst #IE, D0
IF SETCSDEBUGFAIL THEN
Bne.s @aa3
_Debugger
Bra.s @a3
@aa3
ELSE
Beq.s @a3
ENDIF
Move #(1<<SENSE)+(1<<ENABLED), CmdStat(A3,D4)
@aaa3
ELSE
Move #(1<<SENSE)+(1<<IE)+(1<<ENABLED), CmdStat(A3,D4)
ENDIF
Rts
ENDP
EJECT
;________________________________________________________________________
;
; InitRecvChl - Initialize BOTH Recv DMA Channel Register Sets
; Call: A2 - globals
; Return: none
;
;________________________________________________________________________
InitRecvChl PROC
WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr
MoveM.l A3/D4, -(SP)
MoveQ #0, D4 ; init reg set offset
MoveA.l PSCBase(A2), A3
Lea PSC_MACE_RECV(A3), A3 ; A3-> 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<<RCVFWR), D0 ; Keep current FIFO's watermarks
Move.b D0, MACE_FIFO_CNFG(A0) ; Reset MACE recv FIFO
Move #(1<<SENSE)+(1<<SWRESET), PSC_MACE_RECV_CNTL(A1) ; Reset recv chnl
Move #(1<<CIE), PSC_MACE_RECV_CNTL(A1) ; Clear channel int enable
Move #(1<<IE)+(1<<IF), MACE_RECV_CMDSTAT0(A1) ; Clear set int & int enable
Move #(1<<IE)+(1<<IF), MACE_RECV_CMDSTAT1(A1) ; Clear set int & int enable
; reset & disable PSC -> MACE transmit path
Move #(1<<SENSE)+(1<<SWRESET), PSC_MACE_XMIT_CNTL(A1) ; Reset xmit chnl
Move #(1<<CIE), PSC_MACE_XMIT_CNTL(A1) ; Clear channel int enable
Move #(1<<IE)+(1<<IF), MACE_XMIT_CMDSTAT0(A1) ; Clear set int & int enable
Move #(1<<IE)+(1<<IF), MACE_XMIT_CMDSTAT1(A1) ; Clear set int & int enable
Move.b MACE_FIFO_CNFG(A0), D0 ; Get current FIFO config
OrI.b #(1<<XMTFWR), D0 ; Keep current FIFO's watermarks
Move.b D0, MACE_FIFO_CNFG(A0) ; Reset MACE xmit FIFO
; Reset MACE
Move.b #(1<<MACERESET), MACE_BIU_CNFG(A0) ; reset MACE
@wait Move.b MACE_BIU_CNFG(A0), D0
BTst #MACERESET, D0
Bne.s @wait ; loop until reset complete
Move.b #0, MACE_MAC_CNFG(A0) ; make sure MACE disabled
Move.b #MaceIntMask, MACE_INT_MSK(A0) ; Disable all MACE ints.
Rts
ENDP
EJECT
;________________________________________________________________________
;
; FreeMACEMem - free all memory
;
; Call: A2 - our globals
;
; Return: none
;
; Destroys: A0
;
;________________________________________________________________________
FreeMACEMem PROC
IMPORT FreeMemory
WITH MaceVars,FreeMem
Tst.l MaceVarPtr ; Mace var pointer
Beq.s @57 ; no mem allocated
Tst.l MACEmem(A2)
Beq.s @55 ; DMA buffer mem not allocated
Sub.l #FreeMemSz, SP ; room for parms
Move.l MACEmem(A2), memptr(SP) ; ptr to memmgr blk to free
Move.l RecvBuffMem(A2), memptra(SP) ; ptr to mem to unlock
Move.l RecvXmitMemSz(A2), memptrasz(SP) ; size of mem to unlock
Move.l #(1<<Locked)+(1<<Contig)+(1<<CacheOff), memoptions(SP) ; specify options
Lea FreeMemory, A0
Jsr (A0) ; free DMA buffer memory
Add.l #FreeMemSz, SP ; pop parms
@55
Tst.l ChnDescrMem(A2)
Beq.s @56 ; Chain Descriptor buffer mem not allocated
Sub.l #FreeMemSz, SP ; room for parms
Move.l ChnDescrMem(A2), memptr(SP) ; ptr to memmgr blk to free
Move.l #0, memoptions(SP) ; specify options
Lea FreeMemory, A0
Jsr (A0) ; free MACE var memory
Add.l #FreeMemSz, SP ; pop parms
@56
Sub.l #FreeMemSz, SP ; room for parms
Lea MaceVarPtr, A0
Move.l (A0), memptr(SP) ; ptr to memmgr blk to free
Clr.l (A0) ; Clear MaceVarPtr contents
Move.l #0, memoptions(SP) ; specify options
Lea FreeMemory, A0
Jsr (A0) ; free MACE var memory
Add.l #FreeMemSz, SP ; pop parms
@57
Rts
ENDWITH
ENDP
EJECT
;________________________________________________________________________
;
; MACEHalt - HALT the MACE, remove interrupt handlers, free all memory
;
; Call: none
;
; Return: none
;
; Destroys: A1,D0,D1
;
;________________________________________________________________________
MACEHalt PROC EXPORT
WITH MACERegs,MaceVars,PSC_DMA_CHNL,PSC_INT_TBL
Move.l A2, -(SP) ; save regs
MoveA.l MaceVarPtr, A2 ; Get ptr to my vars
Move SR,-(SP) ; Save interrupt mask level
OrI #DMALockOut, SR ; Disable DMA ints.
Bsr ResetMACE
; Remove PSC DMA handlers for Mace Recv & Xmit channels
WITH ExpandMemRec
MoveA.l ([ExpandMem],emDMADispatchGlobals), A0; A0-> 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<<MACE), L3IER(A1) ; Disable MACE interrupts
Move.l D0, MACEhndlr(A0)
Move.l D0, MACEparm(A0) ; MaceVarPtr passed back in A1
OrI #INTLockOut, SR ; Disable ALL ints.
; If deferred task installed, remove it.
Tst.b DTInstalled(A2) ; is Deferred Task installed?
Beq.s @nodq ; nope
IF DEBUG THEN
_Debugger
ENDIF
Lea DTQE(A2), A0 ; get ptr to queue entry
LEA DTQueue, A1 ; get ptr to queue
_Dequeue ; remove from deferred task queue
@nodq
Move (SP)+, SR ; Restore SR
; Free MACE buffer and var memory
; ••••
; •••• WARNING: upper layer handlers better be done with packets cause we're
; •••• freeing the mem the packets are in!
; ••••
Bsr FreeMACEMem ; Free, and unlock if needed, all mem blks
Move.l (SP)+, A2 ; restore regs
Rts
ENDP
EJECT
IF PROM THEN
;________________________________________________________________________
;
; MACESetProm - put Promiscuous receive routine in global var: RcvRtn
; and enable promicuous mode.
;
; Call: 4(SP) - Promiscuous recv routine address
;
; Return: none
;
; Destroys: A0, A1
;
;________________________________________________________________________
MACESetProm PROC EXPORT
WITH MACERegs,MaceVars
MoveA.l MaceVarPtr, A1 ; Get ptr to my vars
Move.l 4(SP), D0 ; get new recv rtn
Move SR,-(SP) ; Save SR
OrI #INTLockOut, SR ; disable all ints
Move.l D0, RcvRtn(A1) ; install new recv rtn
MoveA.l MACEBase(A1), A1
Move.b MACE_MAC_CNFG(A1), D0 ; get current MACE config
OrI.b #(1<<PROMISC), D0
Move.b D0, MACE_MAC_CNFG(A1) ; enable MACE promiscous mode
Move (SP)+, SR ; Restore SR
Rts
ENDP
ENDIF
EJECT
;________________________________________________________________________
;
; FlushRecvChn - "flushes" a chain from a recv DMA chnl reg set by computing a
; false "limit", then calls PrimeRecv to put chain on InUse
; and reprime reg set.
;
; Call: A2 - drvr vars
;
; Return: none
;
; Destroys: A0,D0,D1
;
; Notes: on entry, MACE packet reception MUST BE disabled via MAC Config reg
;
;________________________________________________________________________
FlushRecvChn PROC
WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr
IF COUNTERS THEN
AddQ.l #1, ChnFlushed(A2)
ENDIF
MoveM.l A3/D4, -(SP) ; Save C regs
Move ActRecvSet(A2), D4 ; offset to active reg set
MoveA.l RxChainSet0(A2,D4), A0 ; get ptr to active chain descr
BSet #Flushed, State(A0) ; Indicate flush done on chain
Tst.b RecvBerr(A2) ; are we processing a bus error?
Beq.s @noberr ; no
BSet #Berred, State(A0) ; Indicate bus error on chain
@noberr
MoveA.l PSCBase(A2), A3
Lea PSC_MACE_RECV(A3), A3 ; Recv Channel base address
Move.l Cnt(A3,D4), D1 ; Get current cnt
Move Limit(A0), D0
Sub D1, D0 ; compute temp "flush" limit
Move D0, Limit(A0) ; set temp "flush" limit
; pass A3 & D4
Bsr PrimeRecv ; Put chain on InUse and reprime set
MoveM.l (SP)+, A3/D4 ; Restore C regs
RTS
;________________________________________________________________________
;
; FlushRecvRegSet - Reset MACE recv FIFO and flush PSC recv FIFO,
; and reprogram affected register set.
;
; Call: A2 - drvr vars
;
; Return: none
;
; Destroys: A1,D0,D1
;
; Notes: on entry, MACE packet reception MUST BE disabled via MAC Config reg
;
;________________________________________________________________________
FlushRecvRegSet PROC
WITH MACERegs,MaceVars,PSC_DMA_CHNL
; Reset, ie. flush, MACE Recv FIFO
;???? AMD question: are there any states where doing this reset will cause an "interesting"
; line chng to the PSC, who may be in the middle of reading the recv fifo?
MoveA.l MACEBase(A2), A1
Move.b MACE_FIFO_CNFG(A1), D0 ; Get current FIFO config
OrI.b #(1<<RCVFWR), D0
Move.b D0, MACE_FIFO_CNFG(A1) ; Reset MACE recv FIFO
Tst.b RecvBerr(A2) ; are we processing a bus error?
Bne.s @buserr ; yes, don't flush
MoveA.l PSCBase(A2), A1
Move #(1<<SENSE)+(1<<DMAFLUSH), PSC_MACE_RECV_CNTL(A1) ; Flush PSC Recv FIFO
@chkflush Move PSC_MACE_RECV_CNTL(A1), D0
BTst #DMAFLUSH, D0 ; Is flush complete?
Bne.s @chkflush ; no
@buserr
Bsr.s FlushRecvChn ; flush the chain
Tst.b RecvBerr(A2) ; are we processing a bus error?
Bne.s @buserr1 ; yes, don't unpause
; UnPause the DMA recv channel
MoveA.l PSCBase(A2), A1
Move #(1<<PAUSE), PSC_MACE_RECV_CNTL(A1)
@buserr1
Rts
ENDP
EJECT
;________________________________________________________________________
;
; NormAddr - convert IEEE address to normal format
;
; Call: D0 bit-inverted address byte from Address Prom
;
; Return: D0 bit-inverted address byte
;
; Destroys: D1
;
;________________________________________________________________________
NormAddr PROC EXPORT
MoveM.l D2,-(SP)
Clr.b D1
MoveQ #7,D2
@loop
Lsl.b #1,D1 ; get ready for next bit
Lsr.b #1,D0 ; get a bit from source
Bcc.s @lb ; non there
AddQ.b #1,D1
@lb
DBra D2,@loop
Move.b D1,D0 ; D0=converted value
MoveM.l (SP)+,D2
Rts
ENDP
EJECT
;________________________________________________________________________
;
; DoCRC - compute Ethernet CRC on address field
;
; Call:
; D1 = first two bytes of address
; D3 = last four bytes of address
;
; Return:
; D0 = 6 bit hash into Logical Address Filter
;
; Uses: D0,D1
;
; The CRC-32 of a sequence of bits views that sequence as the co-efficients of a (long!)
; polynomial. This polynomial is multiplied by x^32, then divided by the CRC polynomial
; x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 +x+1.
; It is the remainder of this division (of degree <= x^31), considered as a 32 bit sequence,
; that is the CRC. In the calculation, the initial value of the "remainder" is all 1's.
;
;________________________________________________________________________
CRCPoly EQU %00000100110000010001110110110111
; Co-efficients after a shift left
DoCRC PROC
Move.l D2, -(SP)
MoveQ #-1,D2 ; D2 = current value of CRC
Bsr.s @10 ; Compute over D1, address bits 47-32
Move.l D3,D1 ; D1 = rest to do
Swap D1 ; Get high word of D3 into D1
Bsr.s @10 ; Compute over D1, address bits 31-16
Swap D1 ; Get low word of D3 into D1
Bsr.s @10 ; Compute over D1, address bits 15-0
And #%111111, D2 ; Get six hash bits in low byte
Move D2, D0
Bsr NormAddr ; D0 = bit inverted hash
Lsr.b #2, D0 ; Move 6 msb's to 6 lsb's
Move.l (SP)+, D2
Rts ; Exit DoCRC
;
; Accumulate the CRC over the low 16 bits of D1 (starting with high byte bit 0!)
;
@10 MoveQ #16,D0 ; D0 = no. of bits to do
Ror #8,D1 ; Do high byte first
@15 Lsl.L #1,D2 ; Shift CRC, clear low bit, old hi bit in C
;
; If (CRC-hi-bit XOR D1-current-bit) = 1, we complement bits specified by the CRC polynomial
; (this is the equivalent of a subtract operation in the long division process, I think)
;
Bcc.s @30 ; Branch if CRC hi bit clear
Ror #1,D1 ; Shift D1, low bit in C
Bcs.s @50 ; (1 XOR 1) = 0: don't compl; low bit = 0
Bra.s @40 ; Go complement
@30 Ror #1,D1 ; Shift D1, high bit in C
Bcc.s @50 ; (0 XOR 0) = 0: don't compl; low bit = 0
@40 Eor.l #CRCPoly,D2 ; Complement some bits; set low bit
@50 SubQ #1,D0 ; Decrement count of bits to do
Bne.s @15 ; Do all 16 bits
Rts ; That's it if done them all
ENDP
EJECT
;________________________________________________________________________
;
; WriteLAF - update MACE Logical Address Filter (LAF) from copy in drvr globals
;
; Call:
; A2 -> 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<<ADDRCHG), MACE_ADDR_CNFG(A1) ; Set address change bit
@wait1 Move.b MACE_ADDR_CNFG(A1), D0 ; wait for MACE to clear it
BTst #ADDRCHG, D0
Bne.s @wait1
Lea LogAddrFltr(A2), A0 ; A0-> copy of logical address filter
Move.b #(1<<LOGADDR), MACE_ADDR_CNFG(A1) ; Select logical address
MoveQ #7, D0
@laf Move.b (A0,D0.w), MACE_LOG_ADDR(A1) ; Set appropriate bits in Log. Addr Filter
DBra D0, @laf
Move.b (SP)+, MACE_MAC_CNFG(A1) ; restore MACE mac config
RTS
ENDP
EJECT
;___________________________________________________________________________
;
; MaceAddMulti - add a multicast address to the list
;
; Call:
; D1 = first two bytes of address
; D3 = last four bytes of address
;
; Return:
; none
;
; Computes the hash for this multicast address and increments hash count in
; the Logical Address Filter (LAF) Table. If hash count now = 1, sets
; appropriate bit in the MACE LAF.
;___________________________________________________________________________
MaceAddMulti 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
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) <LW9>
; 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 <LW9>
; OrI #DMALockOut, SR ; Disable DMA ints. <LW9>
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 <LW9>
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<<SENSE)+(1<<IE)+(1<<ENABLED), CmdStat(A0,D2)
Bra.s @aaa3
@a03
ENDIF
@a3 Move #(1<<SENSE)+(1<<IE), CmdStat(A0,D2)
Move CmdStat(A0,D2), D0
BTst #IE, D0
IF SETCSDEBUGFAIL THEN
Bne.s @aa3
_Debugger
Bra.s @a3
@aa3
ELSE
Beq.s @a3
ENDIF
Move #(1<<SENSE)+(1<<ENABLED), CmdStat(A0,D2)
@aaa3
ELSE
Move #(1<<SENSE)+(1<<IE)+(1<<ENABLED), CmdStat(A0,D2)
ENDIF
BChg #4, D2 ; Toggle reg sets
Move D2, NxtXmitSet(A2) ; save offset to next reg set to xmit on
; Move (SP)+,SR ; Restore int. mask level <LW9>
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<<SENSE)+(1<<SWRESET), PSC_MACE_RECV_CNTL(A0) ; Reset PSC recv chnl
Move #0, ActRecvSet(A2) ; make set 0 active reg set
Bsr InitRecvChl ; Initialize the Recv channel
MoveA.l PSCBase(A2), A0
Move #(1<<PAUSE), PSC_MACE_RECV_CNTL(A0) ; UnPause the DMA recv channel
Move.b (SP)+, D0 ; get previous config
MoveA.l MACEBase(A2), A0
Move.b D0, MACE_MAC_CNFG(A0) ; restore config
Clr.b RecvBerr(A2) ; indicate we're DONE processing buserror
Rts
ENDP
EJECT
;___________________________________________________________________________
;
; XmitBusErr - handle bus errors on PSC's MACE DMA transmit channel
;
; Call:
; A0 - PSC base address
; A2 - our variables
; D1 - Transmit DMA Channel control register value
;
; Return:
;
; Notes:
; Should never get called!
;___________________________________________________________________________
XmitBusErr PROC
WITH MACERegs,MaceVars,PSC_DMA_CHNL,XmitBuff
ST XmitBerr(A2) ; indicate we're processing buserror
IF COUNTERS THEN
AddQ.l #1, XmitBerrCnt(A2)
ENDIF
IF BUFDEBUG THEN
Move D1, XmitBerrCntl(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 Lea PSC_MACE_XMIT(A0), A0 ; A0-> 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 <LW9>
Move SR,-(SP) ; Save interrupt mask level <LW9>
OrI #DMALockOut, SR ; Disable DMA ints. <LW9>
Move.l A1, -(SP) ; Push buff ptr <LW9>
Jsr PrimeXmitRS
Bne.s @regsetsfull
AddQ #4, SP ; Strip parms
Move (SP)+, SR ; <LW9>
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 <LW9>
; OrI #DMALockOut, SR ; Disable DMA ints. <LW9>
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<<SENSE)+(1<<ENABLED), CmdStat(A0,D2) ; Enable set, set ints. disabled
BChg #4, D2 ; Toggle reg sets
Move D2, NxtXmitSet(A2) ; save offset to next reg set to xmit on
Move (SP)+, SR ; Restore int. mask level
Move.l (SP)+, A2
MoveQ #0, D0 ; Set CC's
Rts ; Return
ENDP
ENDIF
EJECT
;___________________________________________________________________________
;
; MaceXmitDone - transmit completion routine
;
; Call:
; 4(SP) - xmit buffer ptr
;
; Return:
; no return value/status
;
; Notes: called at interrupt level 4 (PSC DMA)
;___________________________________________________________________________
MaceXmitDone PROC
TxPrm RECORD 4
TxBuff DS.l 1 ; xmit buffer ptr
TxPrmSz EQU *
ENDR
WITH MACERegs,MaceVars,PSC_DMA_CHNL
MoveA.l MaceVarPtr, A0 ; Get ptr to my vars
IF BUFDEBUG THEN
AddQ.l #1, XmtDnActive(A0)
CmpI.l #1, XmtDnActive(A0)
Beq.s @ok
_Debugger ; oooppppsss!
@ok
ENDIF
;
; Link completed xmit buffer back into free list
;
Move.l TxPrm.TxBuff(SP), A1 ; xmt buffer ptr
IF BUFDEBUG THEN
CmpA.l XmitBuff.Next(A1), A1 ; linked to myself?
Bne.s @dok1
_Debugger ; oooppppsss!
@dok1
CmpA.l FreeXmtBuff(A0), A1 ; on free list too?
Bne.s @dok2
_Debugger ; oooppppsss!
@dok2
ENDIF
Move.l FreeXmtBuff(A0), XmitBuff.Next(A1) ; Make us pt to head of freelist
Move.l A1, FreeXmtBuff(A0) ; Make us head of freelist
; Check to see if xmit's waiting
Move.l InUseTxHead(A0), D1 ; Any waiting xmit's?
Beq.s @inuseempty ; No, branch
IF COUNTERS THEN
AddQ.l #1, InUseXmit(A0)
ENDIF
IF BUFDEBUG THEN
Cmp.l A1, D1 ; what we just xmitted should not still be on in use
Bne.s @dok6
_Debugger ; oooppppsss!
@dok6
ENDIF
; Remove this buffer, which is the head, from the xmit InUse queue
Move.l D1, A1
Move.l XmitBuff.Next(A1), D1 ; D1=0, no more items; D1!=0, more items
Move.l D1, InUseTxHead(A0) ; Dequeue xmit
Bne.s @notempty ; Branch if more than 1 xmit waiting
Move.l D1, InUseTxTail(A0) ; Clear tail; if here, head is clear too.
@notempty
Clr.l XmitBuff.Next(A1)
;
; One or more transmit(s) are waiting; send the head of the InUse list
; Note:
; If MaceXmit can't send pkt because both reg sets are in use, it puts the xmit buff
; on the TAIL of the InUse queue. However, we're the xmit completion routine, by definition
; a xmit reg set is now available so we'll call PrimeXmitRS directly and ignore the return code.
;
Move.l A0, -(SP) ; Save MaceVarPtr
Move.l A1, -(SP) ; SP-> 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<<SENSE)+(1<<IE), CmdStat(A3,D4) ; re-enable set ints.
Move (SP)+, SR ; Restore int mask level
MoveM.l (SP)+, A2-A4/D3-D4 ; Restore used C registers
Rts ; That's it
; A4 - ptr to chain, A2 - global ptr
GetPkt
MoveM.l A5-A6, -(SP)
MoveQ #0, D0
MoveQ #11, D1
Move Out(A4), D0 ; get Out, segment number with pkt
Lsl.l D1, D0 ; Out = Out * 2**11 (RxBuffSz=2048)
Add.l LogChnPtr(A4), D0 ; compute address of segment <SM10>
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<<RcvCLSN)+(1<<RcvFRAM)+(1<<RcvFCS), D0 ; get status bits for user
Move.l D0, -(SP) ; pass status to user later
Move (A1)+, D0 ; Get Runt pkt cnt
Move.b D0, 0(SP)
Move (A1), D0 ; Get Collision cnt
Move.b D0, 1(SP)
Btst #RcvOFLO, D1 ; Overflow Error?
Beq.s @s1
AddQ.l #1, dot3StatsInternalMacReceiveErrors(A6)
Bra.s @donext ; can't deliver to user
@s1 AndI.b #(1<<RcvCLSN)+(1<<RcvFRAM)+(1<<RcvFCS), D1 ; Receive Status Error?
Beq.s @s4 ; Note: only lower status/len byte trashed
AddQ.l #1, ifInErrors(A5)
Btst #RcvFCS, D1 ; FCS Error?
Beq.s @s2
AddQ.l #1, dot3StatsFCSErrors(A6)
@s2 Btst #RcvFRAM, D1 ; Framing Error?
Beq.s @s3
AddQ.l #1, dot3StatsAlignmentErrors(A6)
@s3 Btst #RcvCLSN, D1 ; Collsion Error?
Beq.s @s4
AddQ.l #1, COLLCnt(A2) ; Yes
AddQ.l #1, dot3StatsLateCollisions(A6) ; xmit & recv cntr
@s4
AndI #$0f00, D1 ; Get len from upper status/len byte
AndI #$00ff, D2 ; Ignore upper copy of len byte
Or D1, D2 ; Compute length of recv'd pkt
Move D2, -(SP) ; pass recv pkt len
;
; Call user's receive routine
;
Pea Packet(A0) ; Pass recv packet ptr
Move.l A0, -(SP) ; Pass recv buffer ptr
Move.l RcvParm(A2), -(SP) ; Pass user's rcv rtn parm
MoveA.l RcvRtn(A2), A0 ; User's rcv rtn
Jsr (A0) ; Call user's rcv rtn
Add #RcvParms.ParmsSz, SP ; strip parms
@done AddQ #1, Out(A4) ; inc out
MoveM.l (SP)+, A5-A6
Rts
@donext AddQ #4, SP ; pop status
Bra.s @done
ENDP
EJECT
;___________________________________________________________________________
;
; MaceInterrupt - Process interrupts from MACE
;
; Call:
; A1 - Our variables
;
; Return:
; D0=1, indicate interrupt was serviced
;
; Destroys:
;
; Calls:
; none
;
; Notes: Mace interrupts at Level 3
;
; Primary function is to read the MACE trasmit status upon receipt of the
; Transmit Completion interrupt. Also, reads and processes interrupts for
; error conditions.
;___________________________________________________________________________
MaceInterrupt PROC
WITH MACERegs,MaceVars,PSC_DMA_CHNL,Dot3StatsEntry,LAPMIBStats
MoveM.l A0/A2/A3/D1, -(SP) ; Save regs
IF COUNTERS THEN
AddQ.l #1, MaceIntCnt(A1)
ENDIF
Move.l MACEBase(A1), A0 ; Base address of Mace
Move.b MACE_INT(A0), D0 ; Get Mace Interrupt Status
AndI.b #~OurIntsMask, D0 ; Process only the ones we want
Beq @done ; no ints we care about, leave
MoveA.l LAPMIBStatPtr(A1), A2
MoveA.l Dot3StatPtr(A1), A3
;
; Process Transmit Completion Interrupt
;
BTst #XMTINT, D0 ; Xmit done int?
Beq @rcvco ; no, check for err int.
; Read Mace Transmit Status
MoveQ #0, D1
Move.b MACE_TX_RETRY_CNT(A0), D1 ; Read Xmit Retry Count
Add.l D1, XmtRTRYCnt(A1)
Move.b MACE_TX_FRM_STAT(A0), D1 ; Read Xmit Frame Status
BTst #XMTSV, D1 ; Is status valid?
Bne.s @10 ; yes, continue
AddQ.l #1, XmtStatINV(A1)
Bra @rcvco
@10 Move.b D1, -(SP) ; save D1
AndI.b #(1<<UFLO)+(1<<LCOL)+(1<<RTRY), D1
Beq.s @1
AddQ.l #1, ifOutErrors(A2)
@1 Move.b (SP)+, D1 ; restore D1
BTst #UFLO, D1 ; Underflow?
Beq.s @2 ; no
AddQ.l #1, dot3StatsInternalMacTransmitErrors(A3)
@2 BTst #LCOL, D1 ; Late Collision?
Beq.s @3 ; no
AddQ.l #1, XmtLCOL(A1)
AddQ.l #1, dot3StatsLateCollisions(A3)
@3 BTst #LCAR, D1 ; Loss of Carrier?
Beq.s @4 ; no
AddQ.l #1, dot3StatsCarrierSenseErrors(A3)
@4 BTst #DEFER, D1 ; deferred?
Beq.s @5 ; no
AddQ.l #1, dot3StatsDeferredTransmissions(A3)
@5 BTst #RTRY, D1 ; 15 retries?
Beq.s @6 ; no
AddQ.l #1, dot3StatsExcessiveCollisions(A3)
Bra.s @rcvco ; Chk err since remaining
; bits can't be set
@6 BTst #MORE, D1 ; More than 1 retry?
Beq.s @7 ; no
AddQ.l #1, dot3StatsMultipleCollisionFrames(A3)
Bra.s @rcvco ; Chk err since remaining
; bits can't be set
@7 BTst #ONE, D1 ; Exactly 1 retry?
Beq.s @rcvco ; no
AddQ.l #1, dot3StatsSingleCollisionFrames(A3)
;
; Process Error Interrupts
;
@rcvco BTst #RCVCO, D0 ; Recv Collision Overflow count interrupt?
; Indicates RCV coll cntr rolled over from 255->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<<IF)+(1<<IE), CmdStat(A3,D4) ; Clear set int & int ENABLE
; If chain not full:
; we'll get another DMA int. for 2 cases: 1-DT recvs pkt and re-enables
; ints for this set; 2-all of chain's buffers fill up, PSC switches sets, and
; first pkt on new set causes int.
; Else chain is full:
; we'll re-enable ints when set is reprimed.
Move.l Cnt(A3,D4), D1 ; get reg set DMA cnt
Beq.s @chnfull ; bra if chain full
@rcvberrcont
Pea ChkXmitDone ; push return address so we leave ChkRecv
@installDT
Tst.b DTInstalled(A2) ; Is Deferred Task already installed?
IF COUNTERS THEN
Beq.s @33 ; no, go install it
AddQ.l #1, noDTInstall(A2) ; Yes, don't install it again
Bra.s @donerecv
@33
ELSE
Bne.s @donerecv ; Yes, don't install it again
ENDIF
ST DTInstalled(A2) ; Indicate Deferred Task Installed
IF USEDEFERREDTASK THEN
Lea DTQE(A2), A0 ; A0->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<<IF), CmdStat(A3,D4) ; Clear int flag in command/status
; Process Xmit completion interrupt
Lea TxBuffSet0(A2), A0
IF BUFDEBUG THEN
Move.l (A0,D4), D0 ; get xmit buffer address
Bne.s @ok2 ; got one
_Debugger ; no, ActXmitSet screwed up?
@ok2
ENDIF
Move.l (A0,D4), -(SP) ; Push xmit buffer address
Clr.l (A0,D4) ; Indicate MaceXmit can use reg set
BChg #4, D4
Move D4, ActXmitSet(A2) ; update active reg set
Bsr MaceXmitDone
AddQ #4, SP ; Strip parms
Bra.s ChkXmitDone ; go check other reg set
@donePSCInt MoveQ #1, D0 ; Indicate interrupt was serviced
MoveM.l (SP)+, A0/A2-A3/D1-D4
Rts ; Return from PSCInterrupt
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
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<<Locked)+(1<<Contig)+(1<<CacheOff), memoptions(SP) ; want memory locked,
; contiguous, and non-cacheable
Pea MACEmem(A2)
Move.l (SP)+, memhndl(SP)
Pea RecvBuffMem(A2)
Move.l (SP)+, memhndla(SP)
Pea RecvXmitMemSz(A2)
Move.l (SP)+, memhndlasz(SP)
Lea GetMemory, A0
Jsr (A0) ; get memory
Add.l #GetMemSz, SP ; pop parms
ENDWITH
Beq.s @haveMem ; bra if NO error
SubQ #1, D2 ; adjust # xmit buffers first
Bgt.s @GetMem
MoveQ #1, D2 ; set to mininum of one xmit buf
Sub.l D5, D3 ; now adjust # recv buffers, by #
; of recv buffers per chain
; Note: if OneChn, D5 = 1
CmpI #OneChn, D5 ; 1 recv chain?
Bne.s @decchn ; no
CmpI #MinBufpChn,D3 ; less than min # bufs/chn?
Blo.s @err ; yes
Bra.s @GetMem ; try for mem while ≥ MinBufpChn
@decchn SubI #1, MACECfg.RecvChains(A4) ; dec. # of chains
Bgt.s @GetMem ; try for mem while ≥ OneChn
@err Move.w #mFulErr, D0
Bra @InitError ; get out with error
@haveMem
Move D2, MACECfg.XmitBuffs(A4) ; save # of xmit buffs
Move D3, MACECfg.RecvBuffs(A4) ; save # of recv buffs
Move.l RecvBuffMem(A2), D0 ; get ptr to aligned mem
Add.l D4, D0 ; D0 = Recv ptr + recv mem size
Move.l D0, XmitBuffMem(A2) ; save xmit mem ptr
;
; GetMem for recv chain descriptors
;
WITH RecvBuff,RxChnDescr
Move MACECfg.RecvChains(A4), D4
Mulu #RxChnDescrSz, D4 ; D4.l = recv chain descr size
WITH GetMem
Sub.l #GetMemSz, SP ; room for results
Move.l D4, memsize(SP) ; requested memory size
Move.l #0, memoptions(SP) ; do NOT want memory locked,
; contiguous, and non-cacheable
Pea ChnDescrMem(A2)
Move.l (SP)+, memhndl(SP)
Lea GetMemory, A0
Jsr (A0) ; get memory
Add.l #GetMemSz, SP ; pop parms
Blt @InitError ; bra if error
ENDWITH
Move.l ChnDescrMem(A2), D0
Move.l D0, FreeRxChain(A2) ; set up ptr to chain descr's
;
; Initialize recv buffer chains
;
MoveA.l D0, A3 ; get recv chain descr ptr
Move.l RecvBuffMem(A2), LogChnPtr(A3) ; pt chain descr at chain
Move MACECfg.RecvChains(A4), D1 ; # of chains
CmpI #OneChn, D1 ; do we have only 1 chain?
Bne.s @r4 ; no
Move MACECfg.RecvBuffs(A4), D5 ; yes, D5 contain total # of recv buffers
@r4
Move D5, D3 ; get # buffers per chain
MulU #RxBuffSz, D3 ; D3.l = size of chain
@r3
; Initialize chain head
Move D5, savedLimit(A3) ; Set chain limit
Move #0, Out(A3)
IF BUFDEBUG THEN
Move #0, In(A3)
ENDIF
MoveM.l D1/D2, -(SP) ; Save used C-scratch regs
Move.l D3, -(SP) ; logical size of chain
Move.l LogChnPtr(A3), -(SP) ; logical address of chain
Lea TranslateAddress, A0
Jsr (A0) ; get physical address in D0
AddQ #8, SP ; trash parms
MoveM.l (SP)+, D1/D2 ; restore used C-scratch regs
Blt @InitError
Move.l D0, PhyChnPtr(A3) ; save physical address of chain
SubQ #1, D1 ; are we done?
Beq.s @done ; yes
Lea RxChnDescrSz(A3), A0 ; compute ptr to next chain descr
Move.l A0, NextChn(A3) ; make us pt to next chain descr
MoveA.l LogChnPtr(A3), A1
AddA.l D3, A1 ; compute addr of next chain
Move.l A1, LogChnPtr(A0) ; save addr of next chain
Move.l A0, A3 ; pt to next chain descr
Bra.s @r3 ; process next chain
@done
ENDWITH
;
; Link together xmit buffers
;
WITH XmitBuff
Move.l XmitBuffMem(A2), FreeXmtBuff(A2)
MoveA.l FreeXmtBuff(A2), A0 ; Get Xmit header pointer
MoveQ #0, D0
Move MACECfg.XmitBuffs(A4), D0 ; get # xmit buffers
SubQ #1,D0 ; adjust loop count
Bra.s @x1
@x2
Lea TxBuffSz(A0), A1 ; A1-> 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<<RTRD), MACE_USER_TEST_REG(A0) ; Disable access to Reserved Test Regs
Move.b #MaceIntMask, MACE_INT_MSK(A0) ; Disable all ints.
Move.b #XMTS64, MACE_BIU_CNFG(A0) ; Xmit start after 64 bytes, Intel Bus Mode
Move.b MACECfg.XmitFrmCtl(A4), MACE_TX_FRM_CNTRL(A0) ; Xmit Control -> 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<<ADDRCHG), MACE_ADDR_CNFG(A0) ; Set address change bit
@wait1 Move.b MACE_ADDR_CNFG(A0), D0 ; wait for MACE to clear it
BTst #ADDRCHG, D0
Bne.s @wait1
Move.b #(1<<PHYADDR), MACE_ADDR_CNFG(A0) ; Select physical address
Lea MACE_PHY_ADDR(A0), A0 ; A0-> 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<<ADDRCHG), MACE_ADDR_CNFG(A0) ; Set address change bit
@wait2 Move.b MACE_ADDR_CNFG(A0), D0 ; wait for MACE to clear it
BTst #ADDRCHG, D0
Bne.s @wait2
Move.b #(1<<LOGADDR), MACE_ADDR_CNFG(A0) ; Select logical address
Lea MACE_LOG_ADDR(A0), A1 ; A1-> 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<<L4B7)+(1<<DMA), L4IER(A3) ; Enable DMA interrupts
; Initialize Recv & Xmit DMA Channel Control Registers
Move #(1<<SENSE)+(1<<CIE), PSC_MACE_XMIT_CNTL(A3)
Move #(1<<SENSE)+(1<<CIE), PSC_MACE_RECV_CNTL(A3)
Move #(1<<PAUSE), PSC_MACE_XMIT_CNTL(A3) ; UnPause the DMA xmit channel
Move #(1<<PAUSE), PSC_MACE_RECV_CNTL(A3) ; UnPause the DMA recv channel
; Install Mace Interrupt handler, called at Level 3
Lea MaceInterrupt, A1
Move.l A1, MACEhndlr(A0)
Move.l A2, MACEparm(A0) ; MaceVarPtr passed back in A1
Move.b #(1<<L3B7)+(1<<MACE), L3IER(A3) ; Enable MACE interrupts
Move.l MACEBase(A2), A0 ; Base address of Mace
Move.b MACECfg.MACCfgCtl(A4), MACE_MAC_CNFG(A0) ; Default: Enable xmit and recv
Move.b #OurIntsMask, MACE_INT_MSK(A0) ; Enable ints. we care about
MoveQ #0, D0
Bra.s @60
;
; Init error - clear out variable pointer for next try
;
@InitError
Move D0,D3 ; Save error code
Bsr FreeMACEMem ; Free, and unlock if needed, all mem blks
Move D3,D0
CmpI #-1,D0 ; Translate generic error
Bne.s @60
MoveQ #openErr,D0
@60
Tst D0
MoveM.l (SP)+, A2-A4/D3-D5 ; Restore regs
Unlk A6
Rts ; Return with error
ENDP
END