📄 8390.asm
字号:
; Get the command register TXP bit to test for incomplete transmission later
loadport ; Point at Chip's Command Reg
setport EN_CCMD ; ..
pause_
in al, dx
mov ah, al ; Save CR contents in ah for now
; Stop the NIC
pause_
mov al, ENC_STOP+ENC_NODMA
out dx, al ; Write "stop" to command register
; Wait 1.6ms for the NIC to stop transmitting or receiving a packet. National
; says monitoring the ISR RST bit is not reliable, so a wait of the maximum
; packet time (1.2ms) plus some padding is required.
longpause
; Clear the remote byte count registers
xor al,al
setport EN0_RCNTLO ; Point at byte count regs
out dx, al
setport EN0_RCNTHI
pause_
out dx, al
; check the saved state of the TXP bit in the command register
mov rcv_ovr_resend,al ; clear the resend flag
test ah,ENC_TRANS ; Was transmitter still running?
jz rcv_ovr_loopback ; Go if not running
; Transmitter was running, see if it finished or died
setport EN0_ISR ; point at the NIC ISR
pause_
in al,dx ; and get it
test al,ENISR_TX+ENISR_TX_ERR ; Did the transmitter finish?
jnz rcv_ovr_loopback ; one will be set if TX finished
; Transmitter did not complete, remember to resend the packet later.
mov rcv_ovr_resend,ah ; ah has at least ENC_TRANS set
; Put the NIC chip into loopback so It won't keep trying to receive into
; a full ring
rcv_ovr_loopback:
loadport ; resync setport
setport EN0_TXCR ; ..
mov al, ENTXCR_LOOP ; Put transmitter in loopback mode
pause_
out dx, al ; ..
setport EN_CCMD ; Point at Chip command reg
mov al, ENC_START+ENC_NODMA
pause_
out dx, al ; Start the chip running again
; Verify that there is really a packet to receive by fetching the current
; page pointer and comparing it to the next packet pointer.
mov al, ENC_NODMA+ENC_PAGE1 ; Set page one
pause_
out dx,al
setport EN1_CURPAG ; Get current page
pause_
in al,dx
pause_ ; Rewrite current page to fix SMC bug.
out dx,al
mov bl,al ; save it
mov save_curr,al
setport EN_CCMD ;
mov al, ENC_NODMA+ENC_PAGE0
pause_
out dx,al ; Back to page 0
mov al, next_packet ; get saved location for next packet
cmp al,bl ; Check if buffer emptry
jne rcv_ovr_rx_one ; OK go get the NIC header
; NO PACKET IN THE RING AFTER AN OVW INTERRUPT??? Can this ever happen?
; YES! if overrun happend between a receive interrupt and the when the
; current page register is read at the start of recv_frame.
; Count these things too.
add2 soft_rx_over_nd,1
jmp rcv_ovr_empty
; Get the NIC header for the received packet, and check it
rcv_ovr_rx_one:
mov ah,al ; make a byte address. e.g. page
mov bl,ah ; and save in bl
mov al,0 ; 46h becomes 4600h into buffer
mov cx,RCV_HDR_SIZE ; size of rcv_hdr
mov di,offset rcv_hdr ;point to header
movseg es,ds
call block_input
mov al, rcv_hdr+EN_RBUF_STAT ; Get the buffer status byte
test al,ENRSR_RXOK ; Is this frame any good?
jz rcv_ovr_ng ; Skip if not
;
; EVEN if the NIC header status is OK, I have seen garbaged NIC headers, so
; it doesn't hurt to range check the next packet pointer here.
;
mov al, rcv_hdr+EN_RBUF_NXT_PG ; Start of next frame
mov next_packet, al ; Save next packet pointer
cmp al,SM_RSTART_PG ; Below around the bottom?
jb rcv_ovr_ng ; YES - out of range
cmp al,sm_rstop_ptr ; Above the top?
jae rcv_ovr_ng ; YES - out of range
; ok to call rcv_frm
; This gets real tricky here. Because some wise user (like me) may attempt
; to call send_pkt from his receive interrupt service routine, you can't just
; blindly call rcv_frm from here because the NIC is now in LOOPBACK mode!
; to get around this problem I added a global flag that causes rcv_frm to
; make the first call to the users interrupt service routine, get a buffer,
; fill the buffer, BUT defer the second call until later. If a second call
; is required the flag will still be set after return from rcv_frm and you
; can make the upcall after the NIC has been taken out of loopback and has
; resent any required packet.
mov defer_upcall, 1 ; Defer upcalls until later. (may be cleared
; by rcv_frm)
call rcv_frm ; Yes, go accept it
jmp rcv_ovr_ok
rcv_ovr_ng:
or byte ptr soft_rx_err_bits,al
add2 soft_rx_errors,1
mkle LE_RX_ERR, 0, 0, 0 ; Log error packet - gft - 910521
;
; HAD TO ADD ERROR RECOVERY HERE. TO BLINDLY PROCEED AND ASSUME THE NEXT
; PACKET POINTR FROM THE NIC HEADER IS VALID IS INVITING DISASTER.
;
; Error recovery consists of killing and restarting the NIC. This drops all
; the packets in the ring, but thats better than winding up in the weeds!
;
; - gft - 910611
ifdef err_stop
call rcv_mode_1 ; for debugging, stop on error
jmp check_isr ; so we can dump the log
endif
; NO! no longer in memory
; call etopen_0 ; go back to the initial state
;
; Instead copy the last known current page pointer into the next packet pointer
; which will result in skipping all the packets from the errored one to where
; the NIC was storing them when we entered this ISR, but prevents us from
; trying to follow totally bogus next packet pointers through the card RAM
; space.
;
mov al, save_curr ; get the last known current page pointer
mov next_packet, al ; and use it as the next packet pointer
jmp check_isr ; then go handle more interrupts
rcv_ovr_ok:
; moved the next two instructions up to where I range check the
; next packet pointer above - gft - 910611
; mov al,rcv_hdr+EN_RBUF_NXT_PG ; Get pointer to next frame
; mov next_packet, al ; save it in next_packet - gft - 910603
mov al,next_packet ; Grap the next packet pointer
dec al ; Back up one page
cmp al,SM_RSTART_PG ; Did it wrap?
jae rcv_ovr_nwr2
mov al,sm_rstop_ptr ; Yes, back to end of ring
rcv_ovr_empty:
dec al
rcv_ovr_nwr2:
loadport ; Point at boundary reg
setport EN0_BOUNDARY ; ..
pause_
out dx, al ; Set the boundary
; When we get here we have either removed one packet from the ring and updated
; the boundary register, or determined that there really were no new packets
; in the ring.
; Clear the OVW bit in the ISR register.
loadport ; resync the setport macro
setport EN0_ISR ; point at the ISR
mov al, ENISR_OVER ; Clear the overrun interrupt bit
pause_
out dx, al
; Take the NIC out of loopback
setport EN0_TXCR ; Back to TX control reg
xor al, al ; Clear the loopback bit
pause_
out dx, al ; ..
; Any incomplete transmission to resend?
cmp rcv_ovr_resend,0
jz rcv_ovr_deferred ; no, go check for deferred upcall
; Yes, restart the transmission
setport EN_CCMD ; point at command register
mov al, ENC_TRANS+ENC_NODMA+ENC_START
pause_
out dx, al ; Start the transmitter
; If an upcall was deferred, make it now
rcv_ovr_deferred:
cmp defer_upcall,0
jz rcv_ovr_done
mov si,defer_si ; Recover pointer to destination
mov cx,defer_cx ; And it's this long
mov ds,defer_ds ; Tell client it's his source
assume ds:nothing
call recv_copy ; Give it to him
movseg ds,cs
assume ds:code
; log the end of overrun processing, with which flags were set
rcv_ovr_done:
ifdef debug
mov ax, WORD PTR rcv_ovr_resend
mov bx, WORD PTR defer_upcall
mkle LE_RX_OVR_X, ax, bx, 0
endif
mov defer_upcall,0 ; clear the defer upcall flag
; finally go back and check for more interrupts
jmp check_isr ; Done with the overrun case
; End of new receive overrun code
recv_no_overrun:
; Handle receive flags, normal and with error (but not overrun).
test al,ENISR_RX+ENISR_RX_ERR ; Frame received without overrun?
jnz recv_frame_0 ; Go if so.
ifdef board_features
cmp is_overrun_690, 0
jne recv_overrun_11
jmp recv_no_frame ; Go if not.
recv_overrun_11:
jmp recv_690_overrun
else
jmp recv_no_frame ; Go if not.
endif
;
; Move the label recv_frame down to below where the interrupts are cleared.
; This will cause the interrupts to be cleared only after being read in
; check_isr, instead of every time a packet is read from the ring. The way
; it used to work was find a RX or RX_ERR interrupt, clear both, check for
; packet really in ring (compare next packet pointer with current page reg)
; read packet and loop back to clear both ints. When all packets read from
; ring, loop back to check_isr. IF packets keep arriving as fast as or faster
; than we can read them, we never get back to check_isr to see if any higher
; priority interrupts occur (like OVW).
;
; The way it works now is find a RX or RX_ERR interrupt, clear both, check
; for packet really in ring and remember the current page register. Read
; packets from the ring until all packets received at the time the current
; page register was last read have been received, (comparing next packet
; pointer to the once read value of current page register). This eliminates
; both the (possibly unnecessary) resetting of the interrupts and the
; page switch and current page register read on a per packet basis. This should
; also eliminate possible problems with not doing the ring overflow processing
; in heavy traffic referred to in my comments below.
;
; - gft - 910611
;
recv_frame_0:
loadport ; Point at Chip's Command Reg
setport EN0_ISR ; Point at Interrupt status register
pause_
mov al, ENISR_RX+ENISR_RX_ERR
out dx, al ; Clear those requests
setport EN_CCMD ; ..
pause_
cli
mov al, ENC_NODMA+ENC_PAGE1+ENC_START
out dx, al ; Switch to page 1 registers
setport EN1_CURPAG ;Get current page of rcv ring
pause_
in al, dx ; ..
; mov ah, al ; Hold current page in AH
mov save_curr,al ; Hold last read current page register in
; memory instead - gft - 910611
setport EN_CCMD ; Back to page zero registers
pause_
mov al, ENC_NODMA+ENC_PAGE0+ENC_START
out dx, al ; Switch back to page 0 registers
; This becomes the loop back point to read packets from the ring.
; now only loop back and read until those packets received at the time
; the current page register is read above have been read.
; - gft - 910611
recv_frame:
mov al, next_packet ; Get saved pointer to next packet in ring
;
; change the next instruction to compare against the saved copy of the current
; page register and only read from the ring what was received up until the
; last read from the current page register - gft - 910611
;
; cmp al, ah ; Read all the frames?
cmp al, save_curr ; Read all the frames?
jne recv_more_frames; hacked jump code for addition of mkle
; macro below - gft -910521
; jmp recv_frame_break ; Finished them all
;
; changed jmp recv_frame_break to jmp check_isr after recv_frame_break was
; determined to be superfluous. See comments at recv_frame_break below.
; - gft - 910531
;
ifdef board_features
cmp is_overrun_690, 0
je recv_not_690_overrun
recv_690_overrun:
mov is_overrun_690, 0 ; clear overrun indicator
loadport
setport EN0_BOUNDARY ; rewrite bndry with itself
in al, dx
pause_
out dx, al
setport EN0_ISR ; Point at Interrupt status register
pause_
mov al, ENISR_OVER ; Clear overrun interrupt bit
out dx, al
call count_in_err ; Count the anomaly
recv_not_690_overrun:
endif
jmp check_isr ; Finished all receives, check for more
; interrupts.
recv_more_frames:
mov ah,al ; make a byte address. E.G. page
mov al,0 ; 46h becomes 4600h into buffer
mov bl,ah
mov cx,RCV_HDR_SIZE
mov di,offset rcv_hdr
movseg es,ds
call block_input
mov al, rcv_hdr+EN_RBUF_STAT ; Get the buffer status byte
test al,ENRSR_RXOK ; Good frame?
jz recv_err_no_rcv
;
; EVEN if the NIC header status is OK, I have seen garbaged NIC headers, so
; it doesn't hurt to range check the next packet pointer here.
;
mov al, rcv_hdr+EN_RBUF_NXT_PG ; Start of next frame
mov next_packet, al ; Save next packet pointer
cmp al,SM_RSTART_PG ; Below around the bottom?
jb recv_err_no_rcv ; YES - out of range
cmp al,sm_rstop_ptr ; Above the top?
jae recv_err_no_rcv ; YES - out of range
; ok to call rcv_frm
call rcv_frm ; Yes, go accept it
jmp recv_no_rcv
recv_err_no_rcv:
or byte ptr soft_rx_err_bits,al
add2 soft_rx_errors,1
;
; The code used to assume that after decoding the NIC header status
; byte as a receive error, the status, and next packet pointer values
; are actually valid. When using the NIC, this assumption may get one
; up that proverbial creek without a paddle. It has been my experience that
; IF bad status is read in the NIC header, the rest of the NIC header is
; not to be trusted. More likely you read a NIC header from the middle of a
; packet than actually receiving a frame, especially if the save error packet
; bit (SEP) in the receive configuration register is NOT set (it's NOT set in
; this driver).
;
; Error recovery consists of killing and restarting the NIC. This drops all
; the packets in the ring, but thats better than winding up in the weeds!
;
; - gft - 910611
ifdef err_stop
call rcv_mode_1 ; for debugging, stop on error
jmp check_isr ; so we can dump the log
endif
; NO! no longer in memory
; call etopen_0 ; go back to the initial state
;
; Instead copy the last known current page pointer into the next packet pointer
; which will result in skipping all the packets from the errored one to where
; the NIC was storing them when we entered this ISR, but prevents us from
; trying to follow totally bogus next packet pointers through the card RAM
; space.
;
mov al, save_curr ; get the last known current page pointer
mov next_packet, al ; and use it as the next packet pointer
jmp check_isr ; then go handle more interrupts
recv_no_rcv:
; moved the next two instructions up to where I range check the
; next packet pointer above - gft - 910611
; mov al, rcv_hdr+EN_RBUF_NXT_PG ; Start of next frame
; mov next_packet, al ; Save next packet pointer
mov al,next_packet ; Grap the next packet pointer
dec al ; Make previous page for new boundary
; Here's another little bug, which was exposed when when I expanded the
; recieve packet ring for HP 16 bit cards (from 06h-7fh to 06h-ffh).
; The jge instruction is for SIGNED comparisons and failed when the next
; packet pointer got into the range 81h-0feh. Changed the below jge to
; a jae for unsigned comparsions. - gft - 910610
; (Also scanned hppclan.asm and 8390.asm for improper use of signed
; comparisons and found no others.)
cmp al, SM_RSTART_PG ; Wrap around the bottom?
; jge rcv_nwrap4
jae rcv_nwrap4 ; - gft - 910610
mov al, sm_rstop_ptr ; Yes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -