Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1553 → Rev 1554

/kernel/branches/net/drivers/RTL8169.asm
0,0 → 1,1253
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; RTL8169 driver for KolibriOS ;;
;; ;;
;; Copyright 2007 mike.dld, ;;
;; mike.dld@gmail.com ;;
;; ;;
;; Version 0.1 11 February 2007 ;;
;; Version 0.2 3 August 2010 - port to net branch by hidnplayr ;;
;; ;;
;; References: ;;
;; r8169.c - linux driver (etherboot project) ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
format MS COFF
 
API_VERSION equ 0x01000100
DRIVER_VERSION equ 5
 
MAX_DEVICES equ 16
 
DEBUG equ 1
__DEBUG__ equ 1
__DEBUG_LEVEL__ equ 1
 
NUM_TX_DESC equ 4
NUM_RX_DESC equ 4
 
include 'proc32.inc'
include 'imports.inc'
include 'fdo.inc'
include 'netdrv.inc'
 
public START
public service_proc
public version
 
 
REG_MAC0 equ 0x0 ; Ethernet hardware address
REG_MAR0 equ 0x8 ; Multicast filter
REG_TxDescStartAddr equ 0x20
REG_TxHDescStartAddr equ 0x28
REG_FLASH equ 0x30
REG_ERSR equ 0x36
REG_ChipCmd equ 0x37
REG_TxPoll equ 0x38
REG_IntrMask equ 0x3C
REG_IntrStatus equ 0x3E
REG_TxConfig equ 0x40
REG_RxConfig equ 0x44
REG_RxMissed equ 0x4C
REG_Cfg9346 equ 0x50
REG_Config0 equ 0x51
REG_Config1 equ 0x52
REG_Config2 equ 0x53
REG_Config3 equ 0x54
REG_Config4 equ 0x55
REG_Config5 equ 0x56
REG_MultiIntr equ 0x5C
REG_PHYAR equ 0x60
REG_TBICSR equ 0x64
REG_TBI_ANAR equ 0x68
REG_TBI_LPAR equ 0x6A
REG_PHYstatus equ 0x6C
REG_RxMaxSize equ 0xDA
REG_CPlusCmd equ 0xE0
REG_RxDescStartAddr equ 0xE4
REG_ETThReg equ 0xEC
REG_FuncEvent equ 0xF0
REG_FuncEventMask equ 0xF4
REG_FuncPresetState equ 0xF8
REG_FuncForceEvent equ 0xFC
 
; InterruptStatusBits
ISB_SYSErr equ 0x8000
ISB_PCSTimeout equ 0x4000
ISB_SWInt equ 0x0100
ISB_TxDescUnavail equ 0x80
ISB_RxFIFOOver equ 0x40
ISB_LinkChg equ 0x20
ISB_RxOverflow equ 0x10
ISB_TxErr equ 0x08
ISB_TxOK equ 0x04
ISB_RxErr equ 0x02
ISB_RxOK equ 0x01
 
; RxStatusDesc
SD_RxRES equ 0x00200000
SD_RxCRC equ 0x00080000
SD_RxRUNT equ 0x00100000
SD_RxRWT equ 0x00400000
 
; ChipCmdBits
CMD_Reset equ 0x10
CMD_RxEnb equ 0x08
CMD_TxEnb equ 0x04
CMD_RxBufEmpty equ 0x01
 
; Cfg9346Bits
CFG_9346_Lock equ 0x00
CFG_9346_Unlock equ 0xC0
 
; rx_mode_bits
RXM_AcceptErr equ 0x20
RXM_AcceptRunt equ 0x10
RXM_AcceptBroadcast equ 0x08
RXM_AcceptMulticast equ 0x04
RXM_AcceptMyPhys equ 0x02
RXM_AcceptAllPhys equ 0x01
 
; RxConfigBits
RXC_FIFOShift equ 13
RXC_DMAShift equ 8
 
; TxConfigBits
TXC_InterFrameGapShift equ 24
TXC_DMAShift equ 8 ; DMA burst value (0-7) is shift this many bits
 
; PHYstatus
PHYS_TBI_Enable equ 0x80
PHYS_TxFlowCtrl equ 0x40
PHYS_RxFlowCtrl equ 0x20
PHYS_1000bpsF equ 0x10
PHYS_100bps equ 0x08
PHYS_10bps equ 0x04
PHYS_LinkStatus equ 0x02
PHYS_FullDup equ 0x01
 
; GIGABIT_PHY_registers
PHY_CTRL_REG equ 0
PHY_STAT_REG equ 1
PHY_AUTO_NEGO_REG equ 4
PHY_1000_CTRL_REG equ 9
 
; GIGABIT_PHY_REG_BIT
PHY_Restart_Auto_Nego equ 0x0200
PHY_Enable_Auto_Nego equ 0x1000
 
; PHY_STAT_REG = 1;
PHY_Auto_Neco_Comp equ 0x0020
 
; PHY_AUTO_NEGO_REG = 4;
PHY_Cap_10_Half equ 0x0020
PHY_Cap_10_Full equ 0x0040
PHY_Cap_100_Half equ 0x0080
PHY_Cap_100_Full equ 0x0100
 
; PHY_1000_CTRL_REG = 9;
PHY_Cap_1000_Full equ 0x0200
PHY_Cap_1000_Half equ 0x0100
 
PHY_Cap_PAUSE equ 0x0400
PHY_Cap_ASYM_PAUSE equ 0x0800
 
PHY_Cap_Null equ 0x0
 
; _MediaType
MT_10_Half equ 0x01
MT_10_Full equ 0x02
MT_100_Half equ 0x04
MT_100_Full equ 0x08
MT_1000_Full equ 0x10
 
; _TBICSRBit
TBI_LinkOK equ 0x02000000
 
; _DescStatusBit
DSB_OWNbit equ 0x80000000
DSB_EORbit equ 0x40000000
DSB_FSbit equ 0x20000000
DSB_LSbit equ 0x10000000
 
RX_BUF_SIZE equ 1536 ; Rx Buffer size
 
 
ETH_ALEN equ 6
ETH_HLEN equ (2 * ETH_ALEN + 2)
ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for
; mininmum 64bytes frame length
 
; MAC address length
MAC_ADDR_LEN equ 6
 
; max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4)
MAX_ETH_FRAME_SIZE equ 1536
 
TX_FIFO_THRESH equ 256 ; In bytes
 
RX_FIFO_THRESH equ 7 ; 7 means NO threshold, Rx buffer level before first PCI xfer
RX_DMA_BURST equ 7 ; Maximum PCI burst, '6' is 1024
TX_DMA_BURST equ 7 ; Maximum PCI burst, '6' is 1024
ETTh equ 0x3F ; 0x3F means NO threshold
 
EarlyTxThld equ 0x3F ; 0x3F means NO early transmit
RxPacketMaxSize equ 0x0800 ; Maximum size supported is 16K-1
InterFrameGap equ 0x03 ; 3 means InterFrameGap = the shortest one
 
HZ equ 1000
 
RTL_MIN_IO_SIZE equ 0x80
TX_TIMEOUT equ (6*HZ)
 
TIMER_EXPIRE_TIME equ 100
 
ETH_HDR_LEN equ 14
DEFAULT_MTU equ 1500
DEFAULT_RX_BUF_LEN equ 1536
 
 
;#ifdef JUMBO_FRAME_SUPPORT
;#define MAX_JUMBO_FRAME_MTU ( 10000 )
;#define MAX_RX_SKBDATA_SIZE ( MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN )
;#else
MAX_RX_SKBDATA_SIZE equ 1600
;#endif //end #ifdef JUMBO_FRAME_SUPPORT
 
MCFG_METHOD_01 equ 0x01
MCFG_METHOD_02 equ 0x02
MCFG_METHOD_03 equ 0x03
MCFG_METHOD_04 equ 0x04
MCFG_METHOD_05 equ 0x05
MCFG_METHOD_11 equ 0x0b
MCFG_METHOD_12 equ 0x0c
MCFG_METHOD_13 equ 0x0d
MCFG_METHOD_14 equ 0x0e
MCFG_METHOD_15 equ 0x0f
 
PCFG_METHOD_1 equ 0x01 ; PHY Reg 0x03 bit0-3 == 0x0000
PCFG_METHOD_2 equ 0x02 ; PHY Reg 0x03 bit0-3 == 0x0001
PCFG_METHOD_3 equ 0x03 ; PHY Reg 0x03 bit0-3 == 0x0002
 
PCI_COMMAND_IO equ 0x1 ; Enable response in I/O space
PCI_COMMAND_MEM equ 0x2 ; Enable response in mem space
PCI_COMMAND_MASTER equ 0x4 ; Enable bus mastering
PCI_LATENCY_TIMER equ 0x0d ; 8 bits
PCI_COMMAND_SPECIAL equ 0x8 ; Enable response to special cycles
PCI_COMMAND_INVALIDATE equ 0x10 ; Use memory write and invalidate
PCI_COMMAND_VGA_PALETTE equ 0x20 ; Enable palette snooping
PCI_COMMAND_PARITY equ 0x40 ; Enable parity checking
PCI_COMMAND_WAIT equ 0x80 ; Enable address/data stepping
PCI_COMMAND_SERR equ 0x100 ; Enable SERR
PCI_COMMAND_FAST_BACK equ 0x200 ; Enable back-to-back writes
 
virtual at 0
tx_desc:
.status dd ?
.vlan_tag dd ?
.buf_addr dd ?
.buf_Haddr dd ?
.size = $
end virtual
 
virtual at 0
rx_desc:
.status dd ?
.vlan_tag dd ?
.buf_addr dd ?
.buf_Haddr dd ?
.size = $
end virtual
 
virtual at ebx
 
device:
 
ETH_DEVICE
 
.io_addr dd ?
.pci_bus db ?
.pci_dev db ?
.irq_line db ?
 
tpc:
.mmio_addr dd ? ; memory map physical address
.chipset dd ?
.pcfg dd ?
.mcfg dd ?
.cur_rx dd ? ; Index into the Rx descriptor buffer of next Rx pkt
.cur_tx dd ? ; Index into the Tx descriptor buffer of next Rx pkt
.TxDescArrays dd ? ; Index of Tx Descriptor buffer
.RxDescArrays dd ? ; Index of Rx Descriptor buffer
.TxDescArray dd ? ; Index of 256-alignment Tx Descriptor buffer
.RxDescArray dd ? ; Index of 256-alignment Rx Descriptor buffer
 
rb 255-(($ - ebx) and 255) ; align 256
tx_ring rb NUM_TX_DESC * tx_desc.size
 
rb 255-(($ - ebx) and 255) ; align 256
rx_ring rb NUM_RX_DESC * rx_desc.size
 
device_size = $ - device
 
end virtual
 
intr_mask = ISB_LinkChg or ISB_RxOverflow or ISB_RxFIFOOver or ISB_TxErr or ISB_TxOK or ISB_RxErr or ISB_RxOK
rx_config = (RX_FIFO_THRESH shl RXC_FIFOShift) or (RX_DMA_BURST shl RXC_DMAShift) or 0x0000000E
 
 
macro udelay msec {
 
push esi
mov esi, msec
call Sleep
pop esi
 
}
 
macro WRITE_GMII_REG RegAddr, value {
 
set_io REG_PHYAR
if value eq ax
and eax, 0x0000ffff
or eax, 0x80000000 + (RegAddr shl 16)
else
mov eax, 0x80000000 + (RegAddr shl 16) + value
end if
out dx, eax
 
call PHY_WAIT
}
 
macro READ_GMII_REG RegAddr {
 
local .error, .done
 
mov eax, RegAddr shl 16
set_io REG_PHYAR
in eax, dx
 
call PHY_WAIT
jz .error
 
set_io REG_PHYAR
in eax, dx
and eax, 0xFFFF
jmp .done
 
.error:
or eax, -1
.done:
}
 
align 4
PHY_WAIT: ; io addr must already be set to REG_PHYAR
 
udelay 1 ;;;1000
 
push ecx
mov ecx, 2000
; Check if the RTL8169 has completed writing to the specified MII register
@@:
in eax, dx
test eax, 0x80000000
jz .exit
udelay 1 ;;;100
loop @b
.exit:
pop ecx
ret
 
 
 
section '.flat' code readable align 16
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; proc START ;;
;; ;;
;; (standard driver proc) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
align 4
proc START stdcall, state:dword
 
cmp [state], 1
jne .exit
 
.entry:
 
DEBUGF 2,"Loading rtl8169 driver\n"
stdcall RegService, my_service, service_proc
ret
 
.fail:
.exit:
xor eax, eax
ret
 
endp
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; proc SERVICE_PROC ;;
;; ;;
;; (standard driver proc) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
align 4
proc service_proc stdcall, ioctl:dword
 
mov edx, [ioctl]
mov eax, [IOCTL.io_code]
 
;------------------------------------------------------
 
cmp eax, 0 ;SRV_GETVERSION
jne @F
 
cmp [IOCTL.out_size], 4
jl .fail
mov eax, [IOCTL.output]
mov [eax], dword API_VERSION
 
xor eax, eax
ret
 
;------------------------------------------------------
@@:
cmp eax, 1 ;SRV_HOOK
jne .fail
 
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes
jl .fail
 
mov eax, [IOCTL.input]
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given
jne .fail ; other types arent supported for this card yet
 
; check if the device is already listed
 
mov esi, device_list
mov ecx, [devices]
test ecx, ecx
jz .firstdevice
 
; mov eax, [IOCTL.input] ; get the pci bus and device numbers
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)
je .find_devicenum ; Device is already loaded, let's find it's device number
add esi, 4
loop .nextdevice
 
 
; This device doesnt have its own eth_device structure yet, lets create one
.firstdevice:
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card
jge .fail
 
push edx
stdcall KernelAlloc, device_size ; Allocate the buffer for eth_device structure
pop edx
test eax, eax
jz .fail
mov ebx, eax ; ebx is always used as a pointer to the structure (in driver, but also in kernel code)
 
; Fill in the direct call addresses into the struct
 
mov [device.reset], reset
mov [device.transmit], transmit
mov [device.get_MAC], read_mac
mov [device.set_MAC], write_mac
mov [device.unload], unload
mov [device.name], my_service
 
; 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
 
; 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]
mov eax, [device.io_addr]
mov [tpc.mmio_addr], eax
 
; We've found the io address, find IRQ now
 
find_irq [device.pci_bus], [device.pci_dev], [device.irq_line]
 
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]:8
 
; Ok, the eth_device structure is ready, let's probe the device
; Because initialization fires IRQ, IRQ handler must be aware of this device
mov eax, [devices] ; Add the device structure to our device list
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device)
inc [devices] ;
 
call probe ; this function will output in eax
test eax, eax
jnz .err2 ; If an error occured, exit
 
 
mov [device.type], NET_TYPE_ETH
call NetRegDev
 
cmp eax, -1
je .destroy
 
ret
 
; If the device was already loaded, find the device number and return it in eax
 
.find_devicenum:
DEBUGF 2,"Trying to find device number of already registered device\n"
mov ebx, eax
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx
; into a device number in edi
mov eax, edi ; Application wants it in eax instead
DEBUGF 2,"Kernel says: %u\n", eax
ret
 
; If an error occured, remove all allocated data and exit (returning -1 in eax)
 
.destroy:
; todo: reset device into virgin state
 
.err2:
dec [devices]
.err:
DEBUGF 2,"removing device structure\n"
stdcall KernelFree, ebx
 
 
.fail:
or eax, -1
ret
 
;------------------------------------------------------
endp
 
 
align 4
unload:
 
ret
 
 
align 4
init_board:
 
DEBUGF 1,"init_board\n"
 
make_bus_master [device.pci_bus], [device.pci_dev]
 
; Soft reset the chip
set_io 0
set_io REG_ChipCmd
mov al, CMD_Reset
out dx, al
 
; Check that the chip has finished the reset
mov ecx, 1000
set_io REG_ChipCmd
@@: in al, dx
test al, CMD_Reset
jz @f
udelay 10
loop @b
@@:
; identify config method
set_io REG_TxConfig
in eax, dx
and eax, 0x7c800000
DEBUGF 1,"init_board: TxConfig & 0x7c800000 = 0x%x\n", eax
mov esi, mac_info-8
@@: add esi, 8
mov ecx, eax
and ecx, [esi]
cmp ecx, [esi]
jne @b
mov eax, [esi+4]
mov [tpc.mcfg], eax
 
mov [tpc.pcfg], PCFG_METHOD_3
READ_GMII_REG 3
and al, 0x0f
or al, al
jnz @f
mov [tpc.pcfg], PCFG_METHOD_1
jmp .pconf
@@: dec al
jnz .pconf
mov [tpc.pcfg], PCFG_METHOD_2
.pconf:
 
; identify chip attached to board
mov ecx, 10
mov eax, [tpc.mcfg]
@@: dec ecx
js @f
cmp eax, [rtl_chip_info+ecx*8]
jne @b
mov [tpc.chipset], ecx
jmp .match
@@:
; if unknown chip, assume array element #0, original RTL-8169 in this case
DEBUGF 1,"init_board: PCI device: unknown chip version, assuming RTL-8169\n"
set_io REG_TxConfig
in eax, dx
DEBUGF 1,"init_board: PCI device: TxConfig = 0x%x\n", eax
 
mov [tpc.chipset], 0
 
xor eax, eax
inc eax
ret
 
.match:
xor eax,eax
ret
 
 
 
;***************************************************************************
; Function
; probe
; Description
; Searches for an ethernet card, enables it and clears the rx buffer
; If a card was found, it enables the ethernet -> TCPIP link
; Destroyed registers
; eax, ebx, ecx, edx
;
;***************************************************************************
align 4
probe:
 
DEBUGF 1,"probe\n"
 
call init_board
 
call read_mac
 
call PHY_config
 
; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n"
set_io 0
set_io 0x82
mov al, 0x01
out dx, al
cmp [tpc.mcfg], MCFG_METHOD_03
jae @f
; DEBUGF 1,"K : Set PCI Latency=0x40\n"
; stdcall pci_write_config_byte,PCI_LATENCY_TIMER,0x40
@@:
cmp [tpc.mcfg], MCFG_METHOD_02
jne @f
; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n"
set_io 0x82
mov al, 0x01
out dx, al
; DEBUGF 1,"K : Set PHY Reg 0x0bh = 0x00h\n"
WRITE_GMII_REG 0x0b, 0x0000 ; w 0x0b 15 0 0
@@:
; if TBI is not enabled
set_io 0
set_io REG_PHYstatus
in al, dx
test al, PHYS_TBI_Enable
jz .tbi_dis
READ_GMII_REG PHY_AUTO_NEGO_REG
 
; enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
and eax, 0x0C1F
or eax, PHY_Cap_10_Half or PHY_Cap_10_Full or PHY_Cap_100_Half or PHY_Cap_100_Full
WRITE_GMII_REG PHY_AUTO_NEGO_REG, ax
 
; enable 1000 Full Mode
WRITE_GMII_REG PHY_1000_CTRL_REG, PHY_Cap_1000_Full or PHY_Cap_1000_Half ; rtl8168
 
; Enable auto-negotiation and restart auto-nigotiation
WRITE_GMII_REG PHY_CTRL_REG, PHY_Enable_Auto_Nego or PHY_Restart_Auto_Nego
 
udelay 100
mov ecx, 10000
; wait for auto-negotiation process
@@: dec ecx
jz @f
READ_GMII_REG PHY_STAT_REG
udelay 100
test eax, PHY_Auto_Neco_Comp
jz @b
set_io 0
set_io REG_PHYstatus
in al, dx
jmp @f
.tbi_dis:
udelay 100
@@:
 
 
;***************************************************************************
; Function
; rt8169_reset
; Description
; Place the chip (ie, the ethernet card) into a virgin state
; Destroyed registers
; eax, ebx, ecx, edx
;
;***************************************************************************
align 4
reset:
 
DEBUGF 1,"reset\n"
 
lea eax, [tx_ring]
mov [tpc.TxDescArrays], eax
mov [tpc.TxDescArray], eax
 
lea eax, [rx_ring]
mov [tpc.RxDescArrays], eax
mov [tpc.RxDescArray], eax
 
call init_ring
call hw_start
 
mov [device.mtu], 1500
 
xor eax, eax
 
ret
 
 
 
 
 
align 4
PHY_config:
 
DEBUGF 1,"hw_PHY_config: priv.mcfg=%d, priv.pcfg=%d\n",[tpc.mcfg],[tpc.pcfg]
 
cmp [tpc.mcfg], MCFG_METHOD_04
jne .not_4
; WRITE_GMII_REG 0x1F, 0x0001
; WRITE_GMII_REG 0x1b, 0x841e
; WRITE_GMII_REG 0x0e, 0x7bfb
; WRITE_GMII_REG 0x09, 0x273a
WRITE_GMII_REG 0x1F, 0x0002
WRITE_GMII_REG 0x01, 0x90D0
WRITE_GMII_REG 0x1F, 0x0000
jmp .exit
.not_4:
cmp [tpc.mcfg], MCFG_METHOD_02
je @f
cmp [tpc.mcfg], MCFG_METHOD_03
jne .not_2_or_3
@@: WRITE_GMII_REG 0x1F, 0x0001
WRITE_GMII_REG 0x15, 0x1000
WRITE_GMII_REG 0x18, 0x65C7
WRITE_GMII_REG 0x04, 0x0000
WRITE_GMII_REG 0x03, 0x00A1
WRITE_GMII_REG 0x02, 0x0008
WRITE_GMII_REG 0x01, 0x1020
WRITE_GMII_REG 0x00, 0x1000
WRITE_GMII_REG 0x04, 0x0800
WRITE_GMII_REG 0x04, 0x0000
WRITE_GMII_REG 0x04, 0x7000
WRITE_GMII_REG 0x03, 0xFF41
WRITE_GMII_REG 0x02, 0xDE60
WRITE_GMII_REG 0x01, 0x0140
WRITE_GMII_REG 0x00, 0x0077
WRITE_GMII_REG 0x04, 0x7800
WRITE_GMII_REG 0x04, 0x7000
WRITE_GMII_REG 0x04, 0xA000
WRITE_GMII_REG 0x03, 0xDF01
WRITE_GMII_REG 0x02, 0xDF20
WRITE_GMII_REG 0x01, 0xFF95
WRITE_GMII_REG 0x00, 0xFA00
WRITE_GMII_REG 0x04, 0xA800
WRITE_GMII_REG 0x04, 0xA000
WRITE_GMII_REG 0x04, 0xB000
WRITE_GMII_REG 0x03, 0xFF41
WRITE_GMII_REG 0x02, 0xDE20
WRITE_GMII_REG 0x01, 0x0140
WRITE_GMII_REG 0x00, 0x00BB
WRITE_GMII_REG 0x04, 0xB800
WRITE_GMII_REG 0x04, 0xB000
WRITE_GMII_REG 0x04, 0xF000
WRITE_GMII_REG 0x03, 0xDF01
WRITE_GMII_REG 0x02, 0xDF20
WRITE_GMII_REG 0x01, 0xFF95
WRITE_GMII_REG 0x00, 0xBF00
WRITE_GMII_REG 0x04, 0xF800
WRITE_GMII_REG 0x04, 0xF000
WRITE_GMII_REG 0x04, 0x0000
WRITE_GMII_REG 0x1F, 0x0000
WRITE_GMII_REG 0x0B, 0x0000
jmp .exit
.not_2_or_3:
DEBUGF 1,"tpc.mcfg=%d, discard hw PHY config\n", [tpc.mcfg]
.exit:
ret
 
 
 
align 4
set_rx_mode:
 
DEBUGF 1,"set_rx_mode\n"
 
; IFF_ALLMULTI
; Too many to filter perfectly -- accept all multicasts
set_io 0
set_io REG_RxConfig
in eax, dx
mov ecx, [tpc.chipset]
and eax, [rtl_chip_info + ecx * 8 + 4] ; RxConfigMask
or eax, rx_config or (RXM_AcceptBroadcast or RXM_AcceptMulticast or RXM_AcceptMyPhys)
out dx, eax
 
; Multicast hash filter
set_io REG_MAR0 + 0
or eax, -1
out dx, eax
set_io REG_MAR0 + 4
out dx, eax
 
ret
 
 
align 4
init_ring:
 
DEBUGF 1,"init_ring\n"
 
xor eax, eax
mov [tpc.cur_rx], eax
mov [tpc.cur_tx], eax
 
lea edi, [tx_ring]
mov ecx, (NUM_TX_DESC * tx_desc.size) / 4
rep stosd
 
lea edi, [rx_ring]
mov ecx, (NUM_RX_DESC * rx_desc.size) / 4
rep stosd
 
mov edi, [tpc.RxDescArray]
mov ecx, NUM_RX_DESC
@@:
stdcall KernelAlloc, 2048
mov [edi + rx_desc.buf_Haddr], eax
GetRealAddr
mov [edi + rx_desc.buf_addr], eax
mov [edi + rx_desc.status], DSB_OWNbit or RX_BUF_SIZE
add edi, rx_desc.size
loop @b
or [edi - rx_desc.size + rx_desc.status], DSB_EORbit
 
ret
 
 
align 4
hw_start:
 
DEBUGF 1,"hw_start\n"
 
; Soft reset the chip
set_io 0
set_io REG_ChipCmd
mov al, CMD_Reset
out dx, al
 
; Check that the chip has finished the reset
mov ecx, 1000
set_io REG_ChipCmd
@@: in al, dx
test al, CMD_Reset
jz @f
udelay 10
loop @b
@@:
 
set_io REG_Cfg9346
mov al, CFG_9346_Unlock
out dx, al
 
set_io REG_ChipCmd
mov al, CMD_TxEnb or CMD_RxEnb
out dx, al
 
set_io REG_ETThReg
mov al, ETTh
out dx, al
 
; For gigabit rtl8169
set_io REG_RxMaxSize
mov ax, RxPacketMaxSize
out dx, ax
 
; Set Rx Config register
set_io REG_RxConfig
in ax, dx
mov ecx, [tpc.chipset]
and eax, [rtl_chip_info + ecx * 8 + 4] ; RxConfigMask
or eax, rx_config
out dx, eax
 
; Set DMA burst size and Interframe Gap Time
set_io REG_TxConfig
mov eax, (TX_DMA_BURST shl TXC_DMAShift) or (InterFrameGap shl TXC_InterFrameGapShift)
out dx, eax
 
set_io REG_CPlusCmd
in ax, dx
out dx, ax
 
in ax, dx
or ax, 1 shl 3
cmp [tpc.mcfg], MCFG_METHOD_02
jne @f
cmp [tpc.mcfg], MCFG_METHOD_03
jne @f
or ax,1 shl 14
DEBUGF 1,"Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n"
jmp .set
@@:
DEBUGF 1," Set MAC Reg C+CR Offset 0xE0: bit-3\n"
.set:
set_io REG_CPlusCmd
out dx, ax
 
set_io 0xE2
; mov ax, 0x1517
; out dx, ax
; mov ax, 0x152a
; out dx, ax
; mov ax, 0x282a
; out dx, ax
xor ax, ax
out dx, ax
 
xor eax, eax
mov [tpc.cur_rx], eax
lea eax, [tx_ring]
GetRealAddr
set_io REG_TxDescStartAddr
out dx, eax
 
lea eax, [rx_ring]
GetRealAddr
set_io REG_RxDescStartAddr
out dx, eax
 
set_io REG_Cfg9346
mov al, CFG_9346_Lock
out dx, al
 
udelay 10
 
xor eax, eax
set_io REG_RxMissed
out dx, eax
 
call set_rx_mode
 
; no early-rx interrupts
set_io REG_MultiIntr
in ax, dx
and ax, 0xF000
out dx, ax
 
; set interrupt mask
set_io REG_IntrMask
mov ax, intr_mask
out dx, ax
 
xor eax, eax
ret
 
 
align 4
read_mac:
 
set_io 0
set_io REG_MAC0
xor ecx, ecx
lea esi, [device.mac]
mov ecx, MAC_ADDR_LEN
 
; Get MAC address. FIXME: read EEPROM
@@: in al, dx
stosb
inc edx
loop @r
 
DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",[device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2
 
ret
 
align 4
write_mac:
 
ret 6
 
 
 
 
 
;***************************************************************************
; Function
; transmit
; Description
; Transmits a packet of data via the ethernet card
;
; Destroyed registers
; eax, edx, esi, edi
;
;***************************************************************************
align 4
transmit:
 
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8]
mov eax, [esp+4]
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
[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], MAX_ETH_FRAME_SIZE
ja .fail
 
;----------------------------------
; Find currentTX descriptor address
 
mov eax, tx_desc.size
mul [tpc.cur_tx]
lea esi, [eax + tx_ring]
 
;---------------------------
; Program the packet pointer
 
mov eax, [esp]
mov [esi + tx_desc.buf_Haddr], eax
GetRealAddr
mov [esi + tx_desc.buf_addr], eax
 
;------------------------
; Program the packet size
 
mov eax, [esp + 4]
@@: or eax, DSB_OWNbit or DSB_FSbit or DSB_LSbit
cmp [tpc.cur_tx], NUM_TX_DESC - 1
jne @f
or eax, DSB_EORbit
@@: mov [esi + tx_desc.status], eax
 
;----------------------------------------
; Set the polling bit (start transmission
 
set_io 0
set_io REG_TxPoll
mov al, 0x40 ; set polling bit
out dx, al
 
;-----------------------
; Update TX descriptor
 
inc [tpc.cur_tx]
and [tpc.cur_tx], NUM_TX_DESC - 1
 
ret 8
 
.fail:
DEBUGF 1,"transmit failed\n"
or eax, -1
stdcall KernelFree, [esp+4]
ret 8
 
 
;;;DSB_OWNbit
 
 
;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Interrupt handler ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;
 
align 4
int_handler:
 
DEBUGF 1,"IRQ %x ",eax:2
 
; find pointer of device wich made IRQ occur
 
mov ecx, [devices]
test ecx, ecx
jz .fail
mov esi, device_list
.nextdevice:
mov ebx, dword [esi]
 
set_io REG_IntrStatus
in ax, dx
 
test ax, ax
jnz .got_it
 
.continue:
add esi, 4
dec ecx
jnz .nextdevice
 
ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver)
 
.got_it:
DEBUGF 1,"IntrStatus = 0x%x\n",ax
 
cmp ax, 0xFFFF ; if so, hardware is no longer present
je .fail
 
;--------
; Receive
 
test ax, ISB_RxOK
jz .no_rx
 
push ax
 
mov eax, rx_desc.size
mul [tpc.cur_rx]
lea esi, [eax + rx_ring]
 
DEBUGF 1,"RxDesc.status = 0x%x\n", [esi + rx_desc.status]
 
test [esi + rx_desc.status], DSB_OWNbit
jnz .rx_return
 
DEBUGF 1,"tpc.cur_rx = %u\n", [tpc.cur_rx]
 
test eax, SD_RxRES
jnz .rx_return ;;;;; RX error!
 
push .rx_return
and eax, 0x00001FFF
add eax, -4 ; we dont need CRC
push eax
DEBUGF 1,"data length = %u\n", ax
 
push [esi + rx_desc.buf_Haddr]
 
;---------------
; re set OWN bit
 
mov eax, DSB_OWNbit or RX_BUF_SIZE
cmp [tpc.cur_rx], NUM_RX_DESC - 1
jne @f
or eax, DSB_EORbit
@@: mov [esi + rx_desc.status], eax
 
;----------------------
; Allocate a new buffer
 
stdcall KernelAlloc, RX_BUF_SIZE
mov [esi + rx_desc.buf_Haddr], eax
GetRealAddr
sub [esi + rx_desc.buf_addr], eax
 
;--------------
; Update rx ptr
 
inc [tpc.cur_rx]
and [tpc.cur_rx], NUM_RX_DESC - 1
 
jmp EthReceiver
.rx_return:
 
pop ax
.no_rx:
 
;---------
; Transmit
 
test ax, ISB_TxOK
jz .no_tx
push ax
 
DEBUGF 1,"TX ok!\n"
; TODO: free buffers
 
pop ax
.no_tx:
 
;-------
; Finish
 
set_io 0
set_io REG_IntrStatus
out dx, ax ; ACK all interrupts
 
.fail:
ret
 
 
 
 
 
 
 
 
 
; End of code
align 4 ; Place all initialised data here
 
devices dd 0
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF)
my_service db 'RTL8169',0 ; max 16 chars include zero
 
include_debug_strings ; All data wich FDO uses will be included here
 
rtl_chip_info dd \
MCFG_METHOD_01, 0xff7e1880, \ ; RTL8169
MCFG_METHOD_02, 0xff7e1880, \ ; RTL8169s/8110s
MCFG_METHOD_03, 0xff7e1880, \ ; RTL8169s/8110s
MCFG_METHOD_04, 0xff7e1880, \ ; RTL8169sb/8110sb
MCFG_METHOD_05, 0xff7e1880, \ ; RTL8169sc/8110sc
MCFG_METHOD_11, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E
MCFG_METHOD_12, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E
MCFG_METHOD_13, 0xff7e1880, \ ; RTL8101e // PCI-E 8139
MCFG_METHOD_14, 0xff7e1880, \ ; RTL8100e // PCI-E 8139
MCFG_METHOD_15, 0xff7e1880 ; RTL8100e // PCI-E 8139
 
mac_info dd \
0x38800000, MCFG_METHOD_15, \
0x38000000, MCFG_METHOD_12, \
0x34000000, MCFG_METHOD_13, \
0x30800000, MCFG_METHOD_14, \
0x30000000, MCFG_METHOD_11, \
0x18000000, MCFG_METHOD_05, \
0x10000000, MCFG_METHOD_04, \
0x04000000, MCFG_METHOD_03, \
0x00800000, MCFG_METHOD_02, \
0x00000000, MCFG_METHOD_01 ; catch-all
 
section '.data' data readable writable align 16 ; place all uninitialized data place here
 
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling
 
 
/kernel/branches/net/drivers/netdrv.inc
132,39 → 132,16
 
movzx ecx, bus
movzx edx, dev
stdcall PciRead16, ecx ,edx, PCI_REG_COMMAND
stdcall PciRead32, ecx ,edx, PCI_REG_COMMAND
 
or al, PCI_BIT_MASTER or PCI_BIT_PIO
and al, not PCI_BIT_MMIO
or al, PCI_BIT_MASTER ;or PCI_BIT_PIO
; and al, not PCI_BIT_MMIO
stdcall PciWrite32, ecx, edx, PCI_REG_COMMAND, eax
 
; or al, PCI_BIT_MASTER or PCI_BIT_MMIO
; and al, not PCI_BIT_PIO
;; TODO: try to switch to PIO, and check if PIO works or not..
 
stdcall PciWrite16, ecx, edx, PCI_REG_COMMAND, eax
 
}
 
 
; .Latency:
;*******Get current latency setting************************
; mov al, 1 ;read a byte
; mov bh, [pci_dev]
; mov ah, [pci_bus]
; mov bl, 0x0D ;from Lantency Timer Register
; call pci_read_reg
;******see if its aat least 64 clocks********
; cmp ax,64
; jge PCNET_adjust_pci_device_Done
;******Set latency to 32 clocks*******
; mov cx, 64 ;value to write
; mov bh, [pci_dev]
; mov al, 1 ;write a byte
; mov ah, [pci_bus]
; mov bl, 0x0D ;to Lantency Timer Register
; call pci_write_reg
;******Check latency setting***********
; .Done:
 
struc IOCTL {
.handle dd ?
.io_code dd ?
214,8 → 191,6
.packets_tx dd ? ;
.packets_rx dd ? ;
 
; .hwcksum dd ?
 
.end:
}