mirror of
https://github.com/elliotnunn/sys7.1-doc-wip.git
synced 2024-12-13 11:29:15 +00:00
2730 lines
88 KiB
Plaintext
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
|
|
|
|
|
|
|