Updated i8255x driver. Works but has some holes, uses only one receive descriptor. Use with caution.

git-svn-id: svn://kolibrios.org@3206 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2013-01-31 14:10:15 +00:00
parent c4c2da3caa
commit 49fed632cc

View File

@ -10,8 +10,10 @@
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;; Some parts of this driver are based on the code of eepro100.c ;;
;; from linux. ;;
;; ;;
;; Good read about how to program this family of devices: ;;
;; Intel's programming manual for i8255x: ;;
;; http://www.intel.com/design/network/manuals/8255x_opensdm.htm ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -44,25 +46,13 @@ virtual at ebx
ETH_DEVICE
.io_addr dd ?
.pci_bus db ?
.pci_dev db ?
.pci_bus dd ?
.pci_dev dd ?
.irq_line db ?
.rx_buffer dd ?
.tx_buffer dd ?
.rx_desc dd ?
.ee_bus_width dd ?
rb 0x100 - (($ - device) and 0xff)
rxfd:
.status dw ?
.command dw ?
.link dd ?
.rx_buf_addr dd ?
.count dw ?
.size dw ?
.packet dd ?
.ee_bus_width db ?
rb 0x100 - (($ - device) and 0xff)
@ -72,17 +62,16 @@ virtual at ebx
.link dd ?
.tx_desc_addr dd ?
.count dd ?
.tx_buf_addr0 dd ?
.tx_buf_size0 dd ?
.tx_buf_addr1 dd ?
.tx_buf_size1 dd ?
rb 0x100 - (($ - device) and 0xff)
confcmd:
.status: dw ?
.command: dw ?
.link: dd ?
.status dw ?
.command dw ?
.link dd ?
.data rb 64
rb 0x100 - (($ - device) and 0xff)
@ -106,18 +95,36 @@ virtual at ebx
rx_colls_errs dd ?
rx_runt_errs dd ?
last_tx_buffer dd ? ;;; fixme
sizeof.device_struct = $ - device
end virtual
virtual at 0
rxfd:
.status dw ?
.command dw ?
.link dd ?
.rx_buf_addr dd ?
.count dw ?
.size dw ?
.packet:
end virtual
; Serial EEPROM
EE_SK = 1 shl 0 ; serial clock
EE_CS = 1 shl 1 ; chip select
EE_DI = 1 shl 2 ; data in
EE_DO = 1 shl 3 ; data out
EE_MASK = EE_SK + EE_CS + EE_DI + EE_DO
; opcodes, first bit is start bit and must be 1
EE_READ = 110b
EE_WRITE = 101b
EE_ERASE = 111b
@ -128,7 +135,7 @@ CU_START = 0x0010
CU_RESUME = 0x0020
CU_STATSADDR = 0x0040
CU_SHOWSTATS = 0x0050 ; Dump statistics counters.
CU_CMD_BASE = 0x0060 ; Base address to add to add CU commands.
CU_CMD_BASE = 0x0060 ; Base address to add CU commands.
CU_DUMPSTATS = 0x0070 ; Dump then reset stats counters.
RX_START = 0x0001
@ -141,8 +148,8 @@ DRVR_INT = 0x0200 ; Driver generated interrupt
CmdIASetup = 0x0001
CmdConfigure = 0x0002
CmdTx = 0x0004 ;;;;
CmdTxFlex = 0x0008 ;;;
CmdTx = 0x0004
CmdTxFlex = 0x0008
Cmdsuspend = 0x4000
@ -150,23 +157,22 @@ reg_scb_status = 0
reg_scb_cmd = 2
reg_scb_ptr = 4
reg_port = 8
reg_eeprom_ctrl = 12
reg_eeprom = 14
reg_mdi_ctrl = 16
macro delay {
push eax
in eax, dx
in eax, dx
in eax, dx
in eax, dx
in eax, dx
in eax, dx
in eax, dx
in eax, dx
in eax, dx
in eax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
pop eax
}
@ -247,8 +253,11 @@ proc service_proc stdcall, ioctl:dword
mov ax , [eax+1] ;
.nextdevice:
mov ebx, [esi]
cmp ax , word [device.pci_bus] ; compare with pci and device num in device list (notice the usage of word instead of byte)
cmp al, byte[device.pci_bus]
jne @f
cmp ah, byte[device.pci_dev]
je .find_devicenum ; Device is already loaded, let's find it's device number
@@:
add esi, 4
loop .nextdevice
@ -272,27 +281,27 @@ proc service_proc stdcall, ioctl:dword
; save the pci bus and device numbers
mov eax, [IOCTL.input]
mov cl, [eax+1]
mov [device.pci_bus], cl
mov cl, [eax+2]
mov [device.pci_dev], cl
movzx ecx, byte[eax+1]
mov [device.pci_bus], ecx
movzx ecx, byte[eax+2]
mov [device.pci_dev], ecx
; Now, it's time to find the base io addres of the PCI device
find_io [device.pci_bus], [device.pci_dev], [device.io_addr]
PCI_find_io
; We've found the io address, find IRQ now
find_irq [device.pci_bus], [device.pci_dev], [device.irq_line]
PCI_find_irq
DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4
allocate_and_clear [device.rx_buffer], (4096), .err
allocate_and_clear [device.tx_buffer], (4096), .err
; Ok, the eth_device structure is ready, let's probe the device
pushf
cli ; disable ints until initialisation is done
call probe ; this function will output in eax
test eax, eax
jnz .err ; If an error occured, exit
@ -301,6 +310,7 @@ proc service_proc stdcall, ioctl:dword
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device)
inc [devices] ;
popf
mov [device.type], NET_TYPE_ETH
call NetRegDev
@ -323,8 +333,6 @@ proc service_proc stdcall, ioctl:dword
; If an error occured, remove all allocated data and exit (returning -1 in eax)
.err:
stdcall KernelFree, [device.rx_buffer]
stdcall KernelFree, [device.tx_buffer]
stdcall KernelFree, ebx
.fail:
@ -370,14 +378,12 @@ probe:
DEBUGF 1,"Probing i8255x\n"
make_bus_master [device.pci_bus], [device.pci_dev]
PCI_make_bus_master
;---------------------------
; First, identify the device
movzx ecx, [device.pci_bus]
movzx edx, [device.pci_dev]
stdcall PciRead32, ecx ,edx ,0 ; get device/vendor id
stdcall PciRead32, [device.pci_bus], [device.pci_dev], PCI_VENDOR_ID ; get device/vendor id
DEBUGF 1,"Vendor_id=0x%x\n", ax
@ -416,6 +422,18 @@ probe:
align 4
reset:
movzx eax, [device.irq_line]
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1
stdcall AttachIntHandler, eax, int_handler, dword 0
test eax, eax
jnz @f
DEBUGF 1,"\nCould not attach int handler!\n"
; or eax, -1
; ret
@@:
DEBUGF 1,"Resetting %s\n", my_service
;---------------
; reset the card
@ -432,6 +450,7 @@ reset:
lea eax, [lstats]
GetRealAddr
set_io 0
set_io reg_scb_ptr
out dx, eax
@ -441,70 +460,36 @@ reset:
call cmd_wait
;-----------------
; Set CU base to 0
; setup RX
set_io reg_scb_ptr
xor eax, eax
set_io reg_scb_ptr
out dx, eax
set_io reg_scb_cmd
mov ax, INT_MASK + RX_ADDR_LOAD
set_io reg_scb_cmd
out dx, ax
call cmd_wait
;---------------------
; build rxfd structure
;-----------------------------
; Create RX and TX descriptors
mov ax, 0x0001
mov [rxfd.status], ax
mov ax, 0x0000
mov [rxfd.command], ax
call create_ring
lea eax, [rxfd.status]
GetRealAddr
mov [rxfd.link], eax
lea eax, [device.rx_buffer]
GetRealAddr
mov [rxfd.rx_buf_addr], eax
xor ax, ax
mov [rxfd.count], ax
mov ax, 1528
mov [rxfd.size], ax
;-------------------------------
; Set ptr to first command block
; RX start
set_io 0
set_io reg_scb_ptr
lea eax, [rxfd]
mov eax, [device.rx_desc]
GetRealAddr
out dx, eax
set_io reg_scb_cmd
mov ax, INT_MASK + RX_START
set_io reg_scb_cmd
out dx, ax
call cmd_wait
;-------------------
; start the receiver
mov [rxfd.status], 0
mov [rxfd.command], 0xc000
set_io reg_scb_ptr
lea eax, [rxfd]
GetRealAddr
out dx, eax
set_io reg_scb_cmd
mov ax, INT_MASK + RX_START
out dx, ax
call cmd_wait
;-----------------
; set CU base to 0
; Set-up TX
set_io reg_scb_ptr
xor eax, eax
@ -516,22 +501,18 @@ reset:
call cmd_wait
; --------------------
; Set TX Base address
; First, set up confcmd values
mov [txfd.command], CmdIASetup
mov [txfd.status], 0
lea eax, [confcmd]
GetRealAddr
mov [txfd.link], eax
mov word [confcmd.command], Cmdsuspend + CmdConfigure
mov word [confcmd.status], 0
mov [confcmd.command], CmdConfigure + Cmdsuspend
mov [confcmd.status], 0
lea eax, [txfd]
GetRealAddr
mov [confcmd.link], eax
mov esi, confcmd_data
lea edi, [confcmd.data]
mov ecx, 22
rep movsb
mov byte[confcmd.data + 1], 0x88 ; fifo of 8 each
mov byte[confcmd.data + 4], 0
mov byte[confcmd.data + 5], 0x80
@ -539,33 +520,80 @@ reset:
mov byte[confcmd.data + 19], 0x80
mov byte[confcmd.data + 21], 0x05
mov [txfd.command], CmdIASetup
mov [txfd.status], 0
lea eax, [confcmd]
GetRealAddr
mov [txfd.link], eax
; CU start
;;; copy in our MAC
lea edi, [txfd.tx_desc_addr]
lea esi, [device.mac]
movsd
movsw
; lea eax, [txfd]
; GetRealAddr
set_io 0
set_io reg_scb_ptr
lea eax, [txfd]
GetRealAddr
out dx, eax
mov ax, INT_MASK + CU_START
; Start CU & enable ints
set_io reg_scb_cmd
mov ax, CU_START
out dx, ax
call cmd_wait
; wait for thing to start
;-----------------------
; build txfd structure (again!)
; drp004:
;
; cmp [txfd.status], 0
; jz drp004
lea eax, [txfd]
GetRealAddr
mov [txfd.link], eax
mov [txfd.count], 0x02208000
lea eax, [txfd.tx_buf_addr0]
GetRealAddr
mov [txfd.tx_desc_addr], eax
; Indicate that we have successfully reset the card
DEBUGF 1,"Resetting %s complete\n", my_service
;;; enable interrupts
mov [device.mtu], 1514
xor eax, eax ; indicate that we have successfully reset the card
xor eax, eax
ret
align 4
create_ring:
DEBUGF 1,"Creating ring\n"
;---------------------
; build rxfd structure
stdcall KernelAlloc, 2000
mov [device.rx_desc], eax
mov esi, eax
GetRealAddr
mov [esi + rxfd.status], 0x0000
mov [esi + rxfd.command], 0x0000
mov [esi + rxfd.link], eax
mov [esi + rxfd.count], 0
mov [esi + rxfd.size], 1528
;-----------------------
; build txfd structure
lea eax, [txfd]
GetRealAddr
mov [txfd.link], eax
mov [txfd.count], 0x02208000
lea eax, [txfd.tx_buf_addr0]
GetRealAddr
mov [txfd.tx_desc_addr], eax
ret
@ -593,55 +621,54 @@ transmit:
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
[eax+13]:2,[eax+12]:2
cmp dword [esp+8], 1500
cmp dword [esp+8], 1514
ja .error ; packet is too long
cmp dword [esp+8], 60
jb .error ; packet is too short
set_io 0
in ax, dx
and ax, 0xfc00
out dx, ax
mov [txfd.status], 0
mov [txfd.command], Cmdsuspend + CmdTx + CmdTxFlex
lea eax, [txfd]
GetRealAddr
mov [txfd.link], eax
mov [txfd.count], 0x02208000
lea eax, [txfd.tx_buf_addr0]
GetRealAddr
mov [txfd.tx_desc_addr], eax
;;; TODO: check if current descriptor is in use
; fill in buffer address and size
mov eax, [esp+4]
mov [last_tx_buffer], eax ;;; FIXME
GetRealAddr
mov [txfd.tx_buf_addr0], eax
mov eax, [esp+8]
mov [txfd.tx_buf_size0], eax
; Copy the buffer address and size in
mov [txfd.tx_buf_addr1], 0
mov [txfd.tx_buf_size1], 0
mov [txfd.status], 0
mov [txfd.command], Cmdsuspend + CmdTx + CmdTxFlex + 1 shl 15 ;;; EL bit
; mov [txfd.count], 0x02208000 ;;;;;;;;;;;
; Inform device of the new/updated transmit descriptor
lea eax, [txfd]
GetRealAddr
set_io 0
set_io reg_scb_ptr
out dx, eax
mov ax, INT_MASK + CU_START
; Start the transmit
mov ax, CU_START
set_io reg_scb_cmd
out dx, ax
call cmd_wait
in ax, dx
; set_io 0 ;; why?
; in ax, dx ;;
;
; @@:
; cmp [txfd.status], 0 ; wait for completion? dont seems a good idea to me..
; je @r
;
; set_io 0 ;; why?
; in ax, dx ;;
.I8t_001:
cmp [txfd.status], 0
je .I8t_001
; Update stats
inc [device.packets_tx]
mov eax, [esp + 8]
add dword [device.bytes_tx], eax
adc dword [device.bytes_tx + 4], 0
in ax, dx
.finish:
xor eax, eax
ret 8
@ -670,7 +697,7 @@ int_handler:
.nextdevice:
mov ebx, [esi]
set_io 0
; set_io 0 ; reg_scb_status = 0
set_io reg_scb_status
in ax, dx
out dx, ax ; send it back to ACK
@ -685,52 +712,82 @@ int_handler:
.got_it:
DEBUGF 1,"Device: %x Status: %x ", ebx, ax
DEBUGF 1,"Device: %x Status: %x\n", ebx, ax
;;; receive
test ax, 1 shl 14 ; did we receive a frame?
jz .no_rx
cmp [rxfd.status], 0
push ax
DEBUGF 1,"Receiving\n"
push ebx
.rx_loop:
pop ebx
mov esi, [device.rx_desc]
cmp [esi + rxfd.status], 0 ; we could also check bits C and OK (bit 15 and 13)
je .nodata
mov [rxfd.status], 0
mov [rxfd.command], 0xc000
DEBUGF 1,"rxfd status=0x%x\n", [esi + rxfd.status]:4
set_io reg_scb_ptr
lea eax, [rxfd.status]
movzx ecx, [esi + rxfd.count]
and ecx, 0x3fff
push ebx
push .rx_loop
push ecx
add esi, rxfd.packet
push esi
; Update stats
add dword [device.bytes_rx], ecx
adc dword [device.bytes_rx + 4], 0
inc dword [device.packets_rx]
; allocate new descriptor
stdcall KernelAlloc, 2000
mov [device.rx_desc], eax
mov esi, eax
GetRealAddr
mov [esi + rxfd.status], 0x0000
mov [esi + rxfd.command], 0xc000 ; End of list + Suspend
mov [esi + rxfd.link], eax
mov [esi + rxfd.count], 0
mov [esi + rxfd.size], 1528
; restart RX
set_io 0
set_io reg_scb_ptr
; lea eax, [device.rx_desc]
; GetRealAddr
out dx, eax
set_io reg_scb_cmd
mov ax, INT_MASK + RX_START
mov ax, RX_START
out dx, ax
call cmd_wait
movzx ecx, [rxfd.count]
and ecx, 0x3fff
stdcall KernelAlloc, ecx ; Allocate a buffer to put packet into
push ecx
push eax
lea esi, [device.rx_buffer]
.copy:
shr ecx, 1
jnc .nb
movsb
.nb:
shr ecx, 1
jnc .nw
movsw
.nw:
jz .nd
rep movsd
.nd:
; And give packet to kernel
jmp Eth_input
.nodata:
DEBUGF 1, "no more data\n"
pop ax
.no_rx:
; Cleanup after TX
cmp [last_tx_buffer], 0
je .done
stdcall KernelFree, [last_tx_buffer]
mov [last_tx_buffer], 0
.done:
.fail:
ret
@ -755,6 +812,8 @@ cmd_wait:
align 4
ee_read: ; esi = address to read
DEBUGF 1,"Eeprom read from 0x%x", esi
set_io 0
set_io reg_eeprom
@ -762,28 +821,32 @@ ee_read: ; esi = address to read
; Prepend start bit + read opcode to the address field
; and shift it to the very left bits of esi
mov ecx, 32
sub ecx, [device.ee_bus_width]
mov cl, 29
sub cl, [device.ee_bus_width]
shl esi, cl
or esi, EE_READ shl 28
or esi, EE_READ shl 29
mov ecx, [device.ee_bus_width]
movzx ecx, [device.ee_bus_width]
add ecx, 3
mov al, EE_CS
out dx, al
delay
;-----------------------
; Write this to the chip
.loop:
mov eax, EE_CS
mov al, EE_CS + EE_SK
shl esi, 1
jnc @f
or eax, EE_DI
or al, EE_DI
@@:
out dx , eax
out dx, al
delay
or eax, EE_SK
out dx , eax
and al, not EE_SK
out dx, al
delay
loop .loop
@ -795,19 +858,19 @@ ee_read: ; esi = address to read
mov ecx, 16
.loop2:
mov eax, EE_CS + EE_SK
out dx , eax
shl esi, 1
mov al, EE_CS + EE_SK
out dx, al
delay
in eax, dx
test eax, EE_DO
in al, dx
test al, EE_DO
jz @f
inc esi
@@:
shl esi, 1
mov eax, EE_CS
out dx , eax
mov al, EE_CS
out dx, al
delay
loop .loop2
@ -815,11 +878,11 @@ ee_read: ; esi = address to read
;-----------------------
; de-activate the eeprom
xor eax, eax
out dx, eax
xor ax, ax
out dx, ax
DEBUGF 1,"data=%x\n", esi
DEBUGF 1,"=0x%x\n", esi:4
ret
@ -827,6 +890,8 @@ ee_read: ; esi = address to read
align 4
ee_write: ; esi = address to write to, di = data
DEBUGF 1,"Eeprom write 0x%x to 0x%x\n", di, esi
set_io 0
set_io reg_eeprom
@ -834,28 +899,31 @@ ee_write: ; esi = address to write to, di = data
; Prepend start bit + write opcode to the address field
; and shift it to the very left bits of esi
mov ecx, 32
sub ecx, [device.ee_bus_width]
mov cl, 29
sub cl, [device.ee_bus_width]
shl esi, cl
or esi, EE_WRITE shl 28
or esi, EE_WRITE shl 29
mov ecx, [device.ee_bus_width]
movzx ecx, [device.ee_bus_width]
add ecx, 3
mov al, EE_CS ; enable chip
out dx, al
;-----------------------
; Write this to the chip
.loop:
mov eax, EE_CS
mov al, EE_CS + EE_SK
shl esi, 1
jnc @f
or eax, EE_DI
or al, EE_DI
@@:
out dx , eax
out dx, al
delay
or eax, EE_SK
out dx , eax
and al, not EE_SK
out dx, al
delay
loop .loop
@ -866,16 +934,16 @@ ee_write: ; esi = address to write to, di = data
mov ecx, 16
.loop2:
mov eax, EE_CS
mov al, EE_CS + EE_SK
shl di, 1
jnc @f
or eax, EE_DI
or al, EE_DI
@@:
out dx , eax
out dx, al
delay
or eax, EE_SK
out dx , eax
and al, not EE_SK
out dx, al
delay
loop .loop2
@ -883,8 +951,8 @@ ee_write: ; esi = address to write to, di = data
;-----------------------
; de-activate the eeprom
xor eax, eax
out dx, eax
xor al, al
out dx, al
ret
@ -894,28 +962,47 @@ ee_write: ; esi = address to write to, di = data
align 4
ee_get_width:
; DEBUGF 1,"Eeprom get width\n"
set_io 0
set_io reg_eeprom
mov si, EE_READ shl 12
xor ecx, ecx
.loop:
mov ax, EE_CS
out dx, ax
mov al, EE_CS ; activate eeprom
out dx, al
delay
or ax, EE_SK
out dx, ax
mov si, EE_READ shl 13
xor ecx, ecx
.loop:
mov al, EE_CS + EE_SK
shl si, 1
jnc @f
or al, EE_DI
@@:
out dx, al
delay
and al, not EE_SK
out dx, al
delay
inc ecx
in ax, dx
test ax, EE_DO
cmp ecx, 15
jae .give_up
in al, dx
test al, EE_DO
jnz .loop
mov [device.ee_bus_width], ecx
DEBUGF 1,"ee width=%u\n", ecx
.give_up:
xor al, al
out dx, al ; de-activate eeprom
sub cl, 3 ; dont count the opcode bits
mov [device.ee_bus_width], cl
DEBUGF 1,"Eeprom width=%u bit\n", ecx
;-----------------------
@ -936,6 +1023,8 @@ ee_get_width:
align 4
mdio_read:
DEBUGF 1,"MDIO read\n"
shl ecx, 21 ; PHY addr
shl edx, 16 ; PHY reg addr
@ -964,6 +1053,8 @@ mdio_read:
align 4
mdio_write:
DEBUGF 1,"MDIO write\n"
and eax, 0xffff
shl ecx, 21 ; PHY addr
@ -996,15 +1087,15 @@ MAC_read_eeprom:
mov esi, 0
call ee_read
mov word[device.mac], si
mov esi, 1
call ee_read
mov word[device.mac+2], si
mov esi, 14
call ee_read
mov esi, 5
mov esi, 2
call ee_read
mov word[device.mac+4], si
ret
@ -1029,6 +1120,10 @@ version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF)
my_service db 'i8255x', 0 ; max 16 chars include zero
devicename db 'Intel Etherexpress pro/100', 0
confcmd_data db 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1
db 0, 0x2e, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2
db 0x80, 0x3f, 0x05 ; 22 bytes total
device_id_list: