3C59X: Improved interrupt handeling. Small fixes (magic numbers, delays)

git-svn-id: svn://kolibrios.org@9188 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2021-09-12 10:38:04 +00:00
parent 9c0be1dd39
commit 329531cd24

View File

@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;; ;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; ;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;; ;; Distributed under terms of the GNU General Public License ;;
;; ;; ;; ;;
;; 3Com network driver for KolibriOS ;; ;; 3Com network driver for KolibriOS ;;
@ -90,15 +90,20 @@ entry START
COMPATIBLE_API = 0x0100 COMPATIBLE_API = 0x0100
API_VERSION = (COMPATIBLE_API shl 16) + CURRENT_API API_VERSION = (COMPATIBLE_API shl 16) + CURRENT_API
MAX_DEVICES = 16 ; configureable area
MAX_DEVICES = 16 ; Maximum number of devices this driver may handle
FORCE_FD = 0 ; forcing full duplex mode makes sense at some cards and link types FORCE_FD = 0 ; forcing full duplex mode makes sense at some cards and link types
NUM_RX_DESC = 4 ; a power of 2 number NUM_RX_DESC = 32 ; Number of receive descriptors (must be power of 2)
NUM_TX_DESC = 4 ; a power of 2 number NUM_TX_DESC = 16 ; Number of transmit descriptors (must be power of 2)
__DEBUG__ = 1 __DEBUG__ = 1 ; 1 = on, 0 = off
__DEBUG_LEVEL__ = 2 ; 1 = verbose, 2 = errors only __DEBUG_LEVEL__ = 2 ; 1 = verbose, 2 = errors only
; end configureable area
section '.flat' readable writable executable section '.flat' readable writable executable
include '../proc32.inc' include '../proc32.inc'
@ -107,6 +112,17 @@ include '../macros.inc'
include '../fdo.inc' include '../fdo.inc'
include '../netdrv.inc' include '../netdrv.inc'
if (bsr NUM_RX_DESC)>(bsf NUM_RX_DESC)
display 'NUM_RX_DESC must be a power of two'
err
end if
if (bsr NUM_TX_DESC)>(bsf NUM_TX_DESC)
display 'NUM_TX_DESC must be a power of two'
err
end if
; Registers ; Registers
REG_POWER_MGMT_CTRL = 0x7c REG_POWER_MGMT_CTRL = 0x7c
REG_UP_LIST_PTR = 0x38 REG_UP_LIST_PTR = 0x38
@ -402,11 +418,11 @@ proc service_proc stdcall, ioctl:dword
; check if the device is already listed ; check if the device is already listed
mov ecx, [vortex_devices] mov ecx, [devices]
test ecx, ecx test ecx, ecx
jz .maybeboomerang jz .firstdevice
mov esi, vortex_list mov esi, device_list
mov eax, [edx + IOCTL.input] ; get the pci bus and device numbers mov eax, [edx + IOCTL.input] ; get the pci bus and device numbers
mov ax , [eax+1] ; mov ax , [eax+1] ;
.nextdevice: .nextdevice:
@ -419,31 +435,9 @@ proc service_proc stdcall, ioctl:dword
add esi, 4 add esi, 4
loop .nextdevice loop .nextdevice
.maybeboomerang:
mov ecx, [boomerang_devices]
test ecx, ecx
jz .firstdevice
mov esi, boomerang_list
mov eax, [edx + IOCTL.input] ; get the pci bus and device numbers
mov ax, [eax+1] ;
.nextdevice2:
mov ebx, [esi]
cmp al, byte[ebx + device.pci_bus]
jne @f
cmp ah, byte[ebx + device.pci_dev]
je .find_devicenum ; Device is already loaded, let's find it's device number
@@:
add esi, 4
loop .nextdevice2
; This device doesnt have its own eth_device structure yet, lets create one ; This device doesnt have its own eth_device structure yet, lets create one
.firstdevice: .firstdevice:
mov ecx, [boomerang_devices] cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card
add ecx, [vortex_devices]
cmp ecx, MAX_DEVICES ; First check if the driver can handle one more card
jae .fail jae .fail
allocate_and_clear ebx, sizeof.device, .fail ; Allocate the buffer for device structure allocate_and_clear ebx, sizeof.device, .fail ; Allocate the buffer for device structure
@ -481,14 +475,9 @@ proc service_proc stdcall, ioctl:dword
test eax, eax test eax, eax
jnz .err ; If an error occured, exit jnz .err ; If an error occured, exit
mov eax, [devices] ; Add the device structure to our device list
movzx ecx, [ebx + device.ver_id] mov [device_list+4*eax], ebx ;
test word [hw_versions+2+ecx*4], IS_VORTEX inc [devices] ;
jz .not_vortex
mov eax, [vortex_devices] ; Add the device structure to our device list
mov [vortex_list+4*eax], ebx ; (IRQ handler uses this list to find device)
inc [vortex_devices] ;
.register: .register:
mov [ebx + device.type], NET_TYPE_ETH mov [ebx + device.type], NET_TYPE_ETH
@ -500,13 +489,6 @@ proc service_proc stdcall, ioctl:dword
call start_device call start_device
ret ret
.not_vortex:
mov eax, [boomerang_devices] ; Add the device structure to our device list
mov [boomerang_list+4*eax], ebx ; (IRQ handler uses this list to find device)
inc [boomerang_devices]
jmp .register
; If the device was already loaded, find the device number and return it in eax ; If the device was already loaded, find the device number and return it in eax
.find_devicenum: .find_devicenum:
@ -697,13 +679,19 @@ probe:
; or al, 0x14 ; or al, 0x14
out dx, ax out dx, ax
; wait for GlobalReset to complete ; wait for GlobalReset to complete
mov ecx, 64000 mov ecx, 2000
.rsloop: .rsloop:
in ax , dx in ax, dx
test ah , 10000b ; CmdInProgress test ah, 10000b ; CmdInProgress
pusha
mov esi, 1
invoke Sleep
popa
loopz .rsloop loopz .rsloop
DEBUGF 1,"Waiting for nic to boot..\n" DEBUGF 1,"Waiting for NIC to boot..\n"
; wait for 2 seconds for NIC to boot ; wait for 2 seconds for NIC to boot
mov esi, 2000 ; WTF? FIXME mov esi, 2000 ; WTF? FIXME
invoke Sleep ; 2 seconds invoke Sleep ; 2 seconds
@ -1140,38 +1128,36 @@ try_phy:
mov al, MII_BMCR mov al, MII_BMCR
push eax push eax
call mdio_read ; returns with window #4 call mdio_read
or ah, 0x80 ; software reset or ax, BMCR_RESET
mov esi, eax mov esi, eax
mov eax, [esp] mov eax, [esp]
call mdio_write ; returns with window #4 call mdio_write
; wait for reset to complete ; wait for reset to complete
mov esi, 2000 mov esi, 2000
invoke Sleep ; 2s FIXME invoke Sleep ; 2s FIXME
mov eax, [esp] mov eax, [esp]
call mdio_read ; returns with window #4 mov al, MII_BMCR
test ah, 0x80 call mdio_read
test ax, BMCR_RESET
jnz .fail1 jnz .fail1
mov eax, [esp]
; wait for a while after reset ; wait for a while after reset
mov esi, 20 mov esi, 20
invoke Sleep ; 20ms invoke Sleep ; 20ms
mov eax, [esp] mov eax, [esp]
mov al , MII_BMSR mov al, MII_BMSR
call mdio_read ; returns with window #4 call mdio_read
test al, 1 ; extended capability supported? test al, BMSR_ERCAP
jz .fail2 jz .fail2
DEBUGF 1,"Extended capability supported\n" DEBUGF 1,"Extended capability supported\n"
test al, BMSR_ANEGCAPABLE
; auto-neg capable? jz .fail2
test al , 1000b
jz .fail2 ; not auto-negotiation capable
DEBUGF 1,"Auto-negotiation capable\n" DEBUGF 1,"Auto-negotiation capable\n"
test al, BMSR_ANEGCOMPLETE
; auto-neg complete?
test al , 100000b
jnz .auto_neg_ok jnz .auto_neg_ok
DEBUGF 1,"Restarting auto-negotiation\n" DEBUGF 1,"Restarting auto-negotiation\n"
@ -1180,23 +1166,25 @@ try_phy:
mov al, MII_ADVERTISE mov al, MII_ADVERTISE
push eax push eax
call mdio_read ; returns with window #4 call mdio_read ; returns with window #4
or ax , 1111b shl 5; advertise only 10base-T and 100base-TX or ax, ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL
mov esi, eax mov esi, eax
pop eax pop eax
call mdio_write ; returns with window #4 call mdio_write ; returns with window #4
mov eax, [esp] mov eax, [esp]
call mdio_read ; returns with window #4 call mdio_read ; returns with window #4
mov esi, eax mov esi, eax
or bh , 10010b ; restart auto-negotiation or bx, BMCR_ANENABLE or BMCR_ANRESTART
mov eax, [esp] mov eax, [esp]
call mdio_write ; returns with window #4 call mdio_write ; returns with window #4
mov esi, 4000 mov esi, 4000
invoke Sleep ; 4 seconds invoke Sleep ; 4 seconds
mov eax, [esp] mov eax, [esp]
mov al , MII_BMSR
mov al, MII_BMSR
call mdio_read ; returns with window #4 call mdio_read ; returns with window #4
test al , 100000b ; auto-neg complete? test al, BMSR_ANEGCOMPLETE
jnz .auto_neg_ok jnz .auto_neg_ok
jmp .fail3 jmp .fail3
.auto_neg_ok: .auto_neg_ok:
DEBUGF 1,"Auto-negotiation complete\n" DEBUGF 1,"Auto-negotiation complete\n"
@ -2137,15 +2125,14 @@ check_tx_status:
;; ;; ;; ;;
;; Transmit (vortex) ;; ;; Transmit (vortex) ;;
;; ;; ;; ;;
;; In: buffer pointer in [esp+4] ;; ;; In: pointer to device structure in ebx ;;
;; pointer to device structure in ebx ;; ;; Out: eax = 0 on success ;;
;; ;; ;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 16
proc vortex_transmit stdcall bufferptr proc vortex_transmit stdcall bufferptr
pushf spin_lock_irqsave
cli
mov esi, [bufferptr] mov esi, [bufferptr]
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [esi + NET_BUFF.length] DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [esi + NET_BUFF.length]
@ -2156,23 +2143,23 @@ proc vortex_transmit stdcall bufferptr
[eax+13]:2,[eax+12]:2 [eax+13]:2,[eax+12]:2
cmp [esi + NET_BUFF.length], 1514 cmp [esi + NET_BUFF.length], 1514
ja .fail ja .error
cmp [esi + NET_BUFF.length], 60 cmp [esi + NET_BUFF.length], 60
jb .fail jb .error
call check_tx_status call check_tx_status
; switch to register window 7 ; switch to register window 7
set_io [ebx + device.io_addr], 0 set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], REG_COMMAND set_io [ebx + device.io_addr], REG_COMMAND
mov ax, SELECT_REGISTER_WINDOW+7 mov ax, SELECT_REGISTER_WINDOW + 7
out dx, ax out dx, ax
; check for master operation in progress ; check for master operation in progress
set_io [ebx + device.io_addr], REG_MASTER_STATUS set_io [ebx + device.io_addr], REG_MASTER_STATUS
in ax, dx in ax, dx
test ah, 0x80 test ah, 0x80
jnz .fail ; no DMA for sending jnz .overrun ; no DMA for sending
; program frame address to be sent ; program frame address to be sent
set_io [ebx + device.io_addr], REG_MASTER_ADDRESS set_io [ebx + device.io_addr], REG_MASTER_ADDRESS
@ -2190,15 +2177,32 @@ proc vortex_transmit stdcall bufferptr
set_io [ebx + device.io_addr], REG_COMMAND set_io [ebx + device.io_addr], REG_COMMAND
mov ax, (10100b shl 11) + 1 ; StartDMADown mov ax, (10100b shl 11) + 1 ; StartDMADown
out dx, ax out dx, ax
.finish:
popf ; Update stats
inc [ebx + device.packets_tx]
mov eax, [esi + NET_BUFF.length]
add dword[ebx + device.bytes_tx], eax
adc dword[ebx + device.bytes_tx + 4], 0
spin_unlock_irqrestore
xor eax, eax xor eax, eax
ret ret
.fail: .error:
DEBUGF 2,"Send failed\n" DEBUGF 2, "TX packet error\n"
inc [ebx + device.packets_tx_err]
invoke NetFree, [bufferptr] invoke NetFree, [bufferptr]
popf
spin_unlock_irqrestore
or eax, -1
ret
.overrun:
DEBUGF 2, "TX overrun\n"
inc [ebx + device.packets_tx_ovr]
invoke NetFree, [bufferptr]
spin_unlock_irqrestore
or eax, -1 or eax, -1
ret ret
@ -2208,15 +2212,14 @@ endp
;; ;; ;; ;;
;; Transmit (boomerang) ;; ;; Transmit (boomerang) ;;
;; ;; ;; ;;
;; In: buffer pointer in [esp+4] ;; ;; In: pointer to device structure in ebx ;;
;; pointer to device structure in ebx ;; ;; Out: eax = 0 on success ;;
;; ;; ;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 16
proc boomerang_transmit stdcall bufferptr proc boomerang_transmit stdcall bufferptr
pushf spin_lock_irqsave
cli
mov esi, [bufferptr] mov esi, [bufferptr]
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [esi + NET_BUFF.length] DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [esi + NET_BUFF.length]
@ -2227,9 +2230,9 @@ proc boomerang_transmit stdcall bufferptr
[eax+13]:2,[eax+12]:2 [eax+13]:2,[eax+12]:2
cmp [esi + NET_BUFF.length], 1514 cmp [esi + NET_BUFF.length], 1514
ja .fail ja .error
cmp [esi + NET_BUFF.length], 60 cmp [esi + NET_BUFF.length], 60
jb .fail jb .error
call check_tx_status ; Reset TX engine if needed call check_tx_status ; Reset TX engine if needed
@ -2339,14 +2342,32 @@ proc boomerang_transmit stdcall bufferptr
.finish: .finish:
mov [ebx + device.curr_tx], edi mov [ebx + device.curr_tx], edi
popf
; Update stats
inc [ebx + device.packets_tx]
mov eax, [esi + NET_BUFF.length]
add dword[ebx + device.bytes_tx], eax
adc dword[ebx + device.bytes_tx + 4], 0
spin_unlock_irqrestore
xor eax, eax xor eax, eax
ret ret
.fail: .error:
DEBUGF 2,"Send failed\n" DEBUGF 2, "TX packet error\n"
inc [ebx + device.packets_tx_err]
invoke NetFree, [bufferptr] invoke NetFree, [bufferptr]
popf
spin_unlock_irqrestore
or eax, -1
ret
.overrun:
DEBUGF 2, "TX overrun\n"
inc [ebx + device.packets_tx_ovr]
invoke NetFree, [bufferptr]
spin_unlock_irqrestore
or eax, -1 or eax, -1
ret ret
@ -2448,23 +2469,15 @@ read_mac_eeprom:
;; Vortex Interrupt handler ;; ;; Vortex Interrupt handler ;;
;; ;; ;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 16
align 4
int_vortex: int_vortex:
push ebx esi edi push ebx esi edi
DEBUGF 1,"INT\n" mov ebx, [esp+4*4]
DEBUGF 1,"INT for 0x%x\n", ebx
; find pointer of device wich made IRQ occur
mov ecx, [vortex_devices]
test ecx, ecx
jz .nothing
mov esi, vortex_list
.nextdevice:
mov ebx, [esi]
; TODO? if we are paranoid, we can check that the value from ebx is present in the current device_list
set_io [ebx + device.io_addr], 0 set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], REG_INT_STATUS set_io [ebx + device.io_addr], REG_INT_STATUS
@ -2472,21 +2485,7 @@ int_vortex:
and ax, S_5_INTS and ax, S_5_INTS
jnz .nothing jnz .nothing
add esi, 4 DEBUGF 1,"Status: %x\n", eax:4
test ax , ax
jnz .got_it
loop .nextdevice
.nothing:
pop edi esi ebx
xor eax, eax
ret
.got_it:
DEBUGF 1,"Device: %x Status: %x\n", ebx, eax:4
test ax, RxComplete test ax, RxComplete
jz .noRX jz .noRX
@ -2576,10 +2575,7 @@ int_vortex:
out dx, ax out dx, ax
.finish: .finish:
.noRX: .noRX:
test ax, DMADone test ax, DMADone
jz .noDMA jz .noDMA
@ -2595,17 +2591,11 @@ int_vortex:
out dx, ax out dx, ax
.nodmaclear: .nodmaclear:
pop ax pop ax
DEBUGF 1, "DMA Done!\n", cx DEBUGF 1, "DMA Done!\n", cx
.noDMA: .noDMA:
.ACK: .ACK:
set_io [ebx + device.io_addr], 0 set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], REG_COMMAND set_io [ebx + device.io_addr], REG_COMMAND
@ -2613,6 +2603,14 @@ int_vortex:
out dx, ax out dx, ax
pop edi esi ebx pop edi esi ebx
xor eax, eax
inc eax
ret
.nothing:
pop edi esi ebx
xor eax, eax
ret ret
@ -2624,41 +2622,24 @@ int_vortex:
;; Boomerang Interrupt handler ;; ;; Boomerang Interrupt handler ;;
;; ;; ;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 16
align 4
int_boomerang: int_boomerang:
push ebx esi edi push ebx esi edi
DEBUGF 1,"INT\n" mov ebx, [esp+4*4]
DEBUGF 1,"INT for 0x%x\n", ebx
; find pointer of device wich made IRQ occur ; TODO? if we are paranoid, we can check that the value from ebx is present in the current device_list
mov ecx, [boomerang_devices]
test ecx, ecx
jz .nothing
mov esi, boomerang_list
.nextdevice:
mov ebx, [esi]
set_io [ebx + device.io_addr], 0 set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], REG_INT_STATUS set_io [ebx + device.io_addr], REG_INT_STATUS
in ax, dx in ax, dx
test ax, S_5_INTS test ax, S_5_INTS
jnz .got_it jz .nothing
.continue:
add esi, 4
dec ecx
jnz .nextdevice
.nothing:
pop edi esi ebx
xor eax, eax
ret
.got_it: .got_it:
DEBUGF 1,"Status: %x\n", ax
DEBUGF 1,"Device: %x Status: %x\n", ebx, ax
push ax push ax
; disable all INTS ; disable all INTS
@ -2756,7 +2737,7 @@ int_boomerang:
;;;; FIXME: make upunstall work ;;;; FIXME: make upunstall work
.noUpUnStall: .noUpUnStall:
.noRX: .noRX:
test word[esp], DownComplete test word[esp], DownComplete
jz .noTX jz .noTX
DEBUGF 1, "Downcomplete!\n" DEBUGF 1, "Downcomplete!\n"
@ -2777,7 +2758,7 @@ int_boomerang:
dec ecx dec ecx
jnz .txloop jnz .txloop
.noTX: .noTX:
pop ax pop ax
set_io [ebx + device.io_addr], 0 set_io [ebx + device.io_addr], 0
@ -2796,6 +2777,14 @@ int_boomerang:
out dx, ax out dx, ax
pop edi esi ebx pop edi esi ebx
xor eax, eax
inc eax
ret
.nothing:
pop edi esi ebx
xor eax, eax
ret ret
@ -2919,10 +2908,8 @@ HW_VERSIONS_SIZE = $ - hw_versions
include_debug_strings ; All data wich FDO uses will be included here include_debug_strings ; All data wich FDO uses will be included here
align 4 align 4
vortex_devices dd 0 devices dd 0
boomerang_devices dd 0 device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling
vortex_list rd MAX_DEVICES
boomerang_list rd MAX_DEVICES