📄 8390.asm
字号:
;History:538,1
; Ian Brabham 28 Apr 1993 Fix problems related to SMC version of 8390
dp8390_version equ 3 ;version number of the generic 8390 driver.
; Copyright, 1988-1992, Russell Nelson, Crynwr Software
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, version 1.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
; This driver is the work of several people: Bob Clements, Eric Henderson,
; Dave Horne, Glenn Talbott, Russell Nelson, Jan Engvald, Paul Kranenburg,
; and Ian Brabham.
ife SM_RSTART_PG
%err SM_RSTART_PG cannot be zero because of a decrement/unsigned jump.
endif
;
; The longpause macro was originally written as this:
;
;longpause macro
; push cx
; mov cx,0
; loop $
; pop cx
;endm
;
; It was only used to stall while hard resetting the card. On my
; 25Mhz 486 longpause was taking more than 18ms, and almost forever
; on slower machines, much longer than necessary and not predictable.
;
; To be able to utilize longpause elsewhere and make it machine independent and
; predictable, I have re-written it to be a fixed time of 1.6ms, which just
; happens to be the time National recommends waiting for the NIC chip to
; stop sending or receiving after being commanded to stop.
;
; Based on the assumption that ISA specs mandate a 1.0 uS minimum I/O cycle
; Microchannel a 0.5uS minimum I/O cycle, and the NMI Status register (location
; 61h) is readable via I/O cycle on all machines, the longpause macro is now
; defined below. - gft - 901604
; (I realize that on slow machines this may take much longer, but the point
; is that on FAST machines it should never be faster than 1.6ms)
longpause macro
local lp_not_mc
push cx
push ax
mov cx,1600 ; 1.6ms = 1600*1.0us
test sys_features,SYS_MCA
je lp_not_mc
shl cx,1 ; twice as many loops for Microchannel
lp_not_mc:
in al,61h
loop lp_not_mc
pop ax
pop cx
endm
extrn sys_features: byte
sm_rstop_ptr db SM_RSTOP_PG
rxcr_bits db ENRXCR_BCST ; Default to ours plus multicast
ifdef board_features
is_overrun_690 db 0
endif
;-> the assigned Ethernet address of the card.
extrn rom_address: byte
;-> current address
extrn my_address: byte
public mcast_list_bits, mcast_all_flag
mcast_list_bits db 0,0,0,0,0,0,0,0 ;Bit mask from last set_multicast_list
mcast_all_flag db 0 ;Non-zero if hware should have all
; ones in mask rather than this list.
public rcv_modes
rcv_modes dw 7 ;number of receive modes in our table.
dw 0 ;There is no mode zero
dw rcv_mode_1
dw rcv_mode_2
dw rcv_mode_3
dw rcv_mode_4
dw rcv_mode_5
dw rcv_mode_6
;
; a temp buffer for the received header
;
RCV_HDR_SIZE equ 26 ; 2 ids @6 + protocol @2+8, + header @4
rcv_hdr db RCV_HDR_SIZE dup(0)
;
; The board data
;
public board_data
BOARD_DATA_SIZE equ 32
board_data db BOARD_DATA_SIZE dup(0)
; add public for soft errors (how were these extracted before? - gft - 910604
public soft_errors
public soft_tx_errors,soft_tx_err_bits,soft_tx_collisions
public soft_rx_errors,soft_rx_err_bits
public soft_rx_overruns,soft_rx_over_nd
;
; Re-arranged the order of these soft_xx_err things so that they can be
; accessed as a data structure (like the statistics structure defined
; in the packet driver spec. I don't know if it's necessary but I've always
; found data structures to be more portable if elements are size aligned.
; - gft - 910607
; Don't rearrange or insert things between these soft error words because
; they are accessed as a data structure (I don't think I violated my own
; admonition since they wern't public and I could find no references to
; them and only the NEx000 drivers reference the next previous thing,
; board_data, and they only us 16 bytes of that.)
soft_errors label dword
soft_tx_errors dw 0,0
soft_tx_collisions dw 0,0 ; added - gft - 910607 cause who ever heard
; of a CSMA/CD driver not counting
; collisions.
soft_rx_errors dw 0,0
soft_rx_overruns dw 0,0 ; added - gft - 910604 cause I just
; gotta track these so I can findout
; just when I'm pushing a driver or
; application to it's limits
soft_rx_over_nd dw 0,0 ; Also count when theres no data.
hard_tx_errors dw 0,0
soft_tx_err_bits db 0
soft_rx_err_bits db 0
;
; Next Packet Pointer (added - gft - 910603)
;
; Initialize to the same value as the current page pointer (start page 1).
; Update after each reception to be the value of the next packet pointer
; read from the NIC Header.
; Copy value -1 to boundry register after each update.
; Compare value with contents of current page pointer to verify that a
; packet has been received (don't trust ISR RXE/PRX bits). If !=, one
; or more packets have been received.
next_packet db 0
save_curr db 0
; Added flags and temp storage for new receive overrun processing
; - gft - 910604
rcv_ovr_resend db 0,0 ; flag to indicate resend needed
defer_upcall db 0,0 ; flag to indicate deferred upcall needed
defer_ds dw ? ; deferred upcall parameters
defer_si dw ?
defer_cx dw ?
ifdef deb2screen
; Event to screen debugger. Destroys no registers and requires just 3 bytes at
; each place called. Produces a one-line summary of event types that has ever
; occured and then some trace lines with the sequence of the last events./Jan E LDC
SHOWMIN equ 'a'
SHOWMAX equ 'l'
EVENTCOLOR equ 31h
EVENTLINE equ 17
TRACECOLOR equ 2eh
ShowEvent proc near
x = 0
rept (SHOWMAX-SHOWMIN+1)
push ax
mov al,x
jmp short ShowEventNum
x = x+1
endm
ShowEventNum:
pushf
push di
push es
mov ah,EVENTCOLOR
mov di,ax
shl di,1
add al,SHOWMIN
mov es,cs:EventPar
cld
stosw
mov ah,TRACECOLOR
mov es,cs:TracePar
cli
mov di,cs:TraceInd
stosw
and di,01ffh ; (1ff+1)/2 = 256 log entries
mov cs:TraceInd,di
mov al,01bh
not ah
stosw
pop es
pop di
popf
pop ax
ret
ShowEvent endp
EventPar dw 0b800h+(EVENTLINE-1)*10-2*EVENTCOLOR*16
TracePar dw 0b800h+EVENTLINE*10
TraceInd dw 0
SHOW_EVENT macro id
if id gt SHOWMAX or id lt SHOWMIN
.err
endif
call ShowEvent+((id-SHOWMIN)*(ShowEventNum-ShowEvent)/(SHOWMAX-SHOWMIN+1))
endm
else
SHOW_EVENT macro num
endm
endif ; deb2screen
ifdef debug ; Include a very useful logging mechanism.
; The log entry structure. Log entries include useful data such as
; a type (each place a log entry is made uses a different type), various
; chip status, ring buffer status, log entry dependent data, and optionally
; 8259 interrupt controller status.
logentry struc
le_type db 0 ; Log entry type
le_ccmd db ? ; Value of CCMD register
le_isr db ? ; Value of ISR register
le_tsr db ? ; Value of TSR register
le_tcur dw ? ; Value of sm_tcur
le_tboundary dw ? ; Value of sm_tboundary
le_tnum dw ? ; Value of sm_tnum
le_dw dw ? ; Log type specific dw data
ifndef mkle8259 ; Log 8259 status?
le_dd dd ? ; Log type specific dd data
else
le_irr1 db ? ; Value of 8259-1 IRR register
le_isr1 db ? ; Value of 8259-1 ISR register
le_irr2 db ? ; Value of 8259-2 IRR register
le_isr2 db ? ; Value of 8259-2 ISR register
endif
logentry ends
; The types of log entries.
LE_SP_E equ 0 ; send_pkt entry
LE_SP_X equ 1 ; send_pkt exit
LE_ASP_E equ 2 ; as_send_pkt entry
LE_ASP_X equ 3 ; as_send_pkt exit
LE_RBALLOC_E equ 4 ; tx_rballoc entry
LE_RBALLOC_X equ 5 ; tx_rballoc exit
LE_COPY_E equ 6 ; sm_copy entry
LE_COPY_X equ 7 ; sm_copy exit
LE_START_E equ 8 ; tx_start entry
LE_START_X equ 9 ; tx_start exit
LE_XMIT_E equ 0ah ; xmit entry
LE_XMIT_X equ 0bh ; xmit exit
LE_TXISR_E equ 0ch ; txisr entry
LE_TXISR_X equ 0dh ; txisr exit
LE_RECV_E equ 0eh ; recv entry
LE_RECV_X equ 0fh ; recv exit
LE_RCVFRM_E equ 10h ; rcv_frm entry
LE_RCVFRM_X equ 11h ; rcv_frm exit
LE_COPY_L equ 12h ; sm_copy loop
LE_TIMER_E equ 13h ; timer entry
LE_TIMER_X equ 14h ; timer exit
public log, log_index
log logentry 256 dup (<>) ; The log itself
log_index db 0 ; Index to current log entry
; The macro used to create log entries.
mkle macro letype, ledw, ledd, ledd2 ; Make an entry in the log
pushf ; Save interrupt enable state
cli ; Disable interrupts
push dx ; Save registers
push bx
push ax
mov bl, log_index ; Get current log_index
xor bh, bh ; Clear high byte
shl bx, 1 ; Multiply by sixteen
shl bx, 1
shl bx, 1
shl bx, 1
mov log[bx].le_type, letype ; Store log entry type
loadport ; Base of device
setport EN_CCMD ; Point at chip command register
in al, dx ; Get chip command state
mov log[bx].le_ccmd, al ; Store CCMD value
setport EN0_ISR ; Point at chip command register
in al, dx ; Get chip command state
mov log[bx].le_isr, al ; Store ISR value
setport EN0_TSR ; Point at chip command register
in al, dx ; Get chip command state
mov log[bx].le_tsr, al ; Store TSR value
mov ax, sm_tcur ; Get current sm_tcur
mov log[bx].le_tcur, ax ; Store sm_tcur value
mov ax, sm_tboundary ; Get current sm_tboundary
mov log[bx].le_tboundary, ax ; Store sm_tboundary value
mov ax, sm_tnum ; Get current sm_tnum
mov log[bx].le_tnum, ax ; Store sm_tnum value
mov log[bx].le_dw, ledw ; Store log entry dw
ifndef mkle8259 ; Include extra per-type data
mov word ptr log[bx].le_dd, ledd ; Store low word of log entry dd
mov word ptr log[bx].le_dd+2, ledd2 ; Store high word of log entry dd
else ; Include 8259 status
mov al,0ah ; read request register from
out 0a0h,al ; secondary 8259
pause_
in al,0a0h ; get it
mov log[bx].le_irr2, al
mov al,0bh ; read in-service register from
out 0a0h,al ; secondary 8259
pause_
in al,0a0h ; get it
mov log[bx].le_isr2, al
mov al,0ah ; read request register from
out 020h,al ; primary 8259
pause_
in al,020h ; get it
mov log[bx].le_irr1, al
mov al,0bh ; read in-service register from
out 020h,al ; primary 8259
pause_
in al,020h ; get it
mov log[bx].le_isr1, al
endif
ifdef screenlog ; Log the entry type to the screen too
push es
mov ax, 0b800h ; Color screen only...
mov es, ax
mov bl, log_index ; Get current log_index
xor bh, bh ; Clear high byte
shl bx, 1 ; Multiply by sixteen
add bx, 3360
mov byte ptr es:[bx-1], 07h
mov byte ptr es:[bx], letype+30h
mov byte ptr es:[bx+1], 70h
pop es
endif
inc log_index ;
pop ax ; Restore registers
pop bx
pop dx
popf ; Restore interrupt enable state
endm
else
mkle macro letype, ledw, ledd, ledd2 ; Define an empty macro
endm
endif
public bad_command_intercept
bad_command_intercept:
;called with ah=command, unknown to the skeleton.
;exit with nc if okay, cy, dh=error if not.
mov dh,BAD_COMMAND
stc
ret
public as_send_pkt
; The Asynchronous Transmit Packet routine.
; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
; interrupts possibly enabled.
; Exit with nc if ok, or else cy if error, dh set to error number.
; es:di and interrupt enable flag preserved on exit.
as_send_pkt:
ret
public drop_pkt
; Drop a packet from the queue.
; Enter with es:di -> iocb.
drop_pkt:
assume ds:nothing
ret
public xmit
; Process a transmit interrupt with the least possible latency to achieve
; back-to-back packet transmissions.
; May only use ax and dx.
xmit:
assume ds:nothing
ret
; The tx_wait loop had three problems that affected high load throughput.
; Most seriously, while we are waiting for the previous SEND to finnish,
; the chip can actually be RECEIVING one or even many packets! But because
; we were waiting with interrupts disabled, these packets were not emptied
; from the receive ring and we could get an overrun. We could put in code to
; test for pending receive interrupts, but that would not help for the
; third problem, see below. Instead interrupts are now on while waiting.
; Secondly, the wait loop was not long enough to allow for up to 16 collisions.
; Thirdly, for a router there are two or more drivers and the busy waiting
; in one of them prevented interrupt handling for the other(s), giving
; unnecessary low throughput. /Jan E LDC
tx_wait:
mov bx,1024*7 ; max coll time in Ethernet slot units
tx_wait_l1:
mov ah,51 ; assume 1 us IO
test sys_features,SYS_MCA
jz tx_wait_l2
shl ah,1 ; MCA IO is just 0.5 us
tx_wait_l2:
sti ; allow receive interrupts while waiting
loadport ; Point at chip command register
setport EN_CCMD ; ..
in al, dx ; Get chip command state
test al,ENC_TRANS ; Is transmitter still running?
cli ; the rest of the code may not work with EI (?)
jz tx_idle_0 ; Go if free
dec ah
jnz tx_wait_l2 ; wait 51.2 us (one ethernet slot time)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -