kolibrios/kernel/trunk/network/eth_drv/drivers/forcedeth.inc

2684 lines
70 KiB
PHP
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; FORCEDETH.INC ;;
;; ;;
;; Ethernet driver for Kolibri OS ;;
;; ;;
;; Version 0.1 24 June 2008 - 23 Sep 2008 ;;
;; ;;
;; Driver for chips of NVIDIA nForce2 ;;
;; References: ;;
;; forcedeth.c - linux driver (etherboot project) ;;
;; ethernet driver template by Mike Hibbett ;;
;; ;;
;; The copyright statement is ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;; Copyright 2008 shurf, ;;
;; cit.utc@gmail.com ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
;********************************************************************
; Interface
; forcedeth_reset
; forcedeth_probe
; forcedeth_poll
; forcedeth_transmit
; forcedeth_cable
;
;********************************************************************
;**************************************************************************
; forcedeth Register Definitions
;**************************************************************************
PCI_REG_COMMAND equ 0x04 ; command register
PCI_COMMAND_IO equ 0x01 ; Enable response in I/O space
PCI_COMMAND_MASTER equ 0x04 ; Enable bus mastering
PCI_LATENCY_TIMER equ 0x0d ; 8 bits
PCI_VENDOR_ID equ 0x00 ; 16 bit
PCI_REVISION_ID equ 0x08 ; 8 bits
PCI_BASE_ADDRESS_0 equ 0x10 ; 32 bits
PCI_BASE_ADDRESS_1 equ 0x14 ; 32 bits
PCI_BASE_ADDRESS_2 equ 0x18 ; 32 bits
PCI_BASE_ADDRESS_3 equ 0x1c ; 32 bits
PCI_BASE_ADDRESS_4 equ 0x20 ; 32 bits
PCI_BASE_ADDRESS_5 equ 0x24 ; 32 bits
PCI_BASE_ADDRESS_SPACE_IO equ 0x01
PCI_BASE_ADDRESS_IO_MASK equ (not 0x03)
PCI_BASE_ADDRESS_MEM_MASK equ (not 0x0f)
PCI_BASE_ADDRESS_MEM_TYPE_MASK equ 0x06
PCI_BASE_ADDRESS_MEM_TYPE_32 equ 0x00 ; 32 bit address
PCI_BASE_ADDRESS_MEM_TYPE_1M equ 0x02 ; Below 1M [obsolete]
PCI_BASE_ADDRESS_MEM_TYPE_64 equ 0x04 ; 64 bit address
; NIC specific static variables go here
PCI_DEVICE_ID_NVIDIA_NVENET_1 equ 0x01c3
PCI_DEVICE_ID_NVIDIA_NVENET_2 equ 0x0066
PCI_DEVICE_ID_NVIDIA_NVENET_4 equ 0x0086
PCI_DEVICE_ID_NVIDIA_NVENET_5 equ 0x008c
PCI_DEVICE_ID_NVIDIA_NVENET_3 equ 0x00d6
PCI_DEVICE_ID_NVIDIA_NVENET_7 equ 0x00df
PCI_DEVICE_ID_NVIDIA_NVENET_6 equ 0x00e6
PCI_DEVICE_ID_NVIDIA_NVENET_8 equ 0x0056
PCI_DEVICE_ID_NVIDIA_NVENET_9 equ 0x0057
PCI_DEVICE_ID_NVIDIA_NVENET_10 equ 0x0037
PCI_DEVICE_ID_NVIDIA_NVENET_11 equ 0x0038
PCI_DEVICE_ID_NVIDIA_NVENET_12 equ 0x0268
PCI_DEVICE_ID_NVIDIA_NVENET_13 equ 0x0269
PCI_DEVICE_ID_NVIDIA_NVENET_14 equ 0x0372
PCI_DEVICE_ID_NVIDIA_NVENET_15 equ 0x0373
ETH_DATA_LEN equ 1500
; rx/tx mac addr + type + vlan + align + slack
RX_NIC_BUFSIZE equ (ETH_DATA_LEN + 64)
; even more slack
RX_ALLOC_BUFSIZE equ (ETH_DATA_LEN + 128)
NvRegIrqStatus equ 0x00
NvRegIrqMask equ 0x04
NvRegUnknownSetupReg6 equ 0x08
NvRegPollingInterval equ 0x0c
NvRegMacReset equ 0x3c
NvRegMisc1 equ 0x80
NvRegTransmitterControl equ 0x84
NvRegTransmitterStatus equ 0x88
NvRegPacketFilterFlags equ 0x8c
NvRegOffloadConfig equ 0x90
NvRegReceiverControl equ 0x94
NvRegReceiverStatus equ 0x98
NvRegRandomSeed equ 0x9c
NvRegUnknownSetupReg1 equ 0xA0
NvRegUnknownSetupReg2 equ 0xA4
NvRegMacAddrA equ 0xA8 ; MAC address low
NvRegMacAddrB equ 0xAC ; MAC address high
NvRegMulticastAddrA equ 0xB0
NvRegMulticastAddrB equ 0xB4
NvRegMulticastMaskA equ 0xB8
NvRegMulticastMaskB equ 0xBC
NvRegPhyInterface equ 0xC0
NvRegTxRingPhysAddr equ 0x100
NvRegRxRingPhysAddr equ 0x104
NvRegRingSizes equ 0x108
NvRegUnknownTransmitterReg equ 0x10c
NvRegLinkSpeed equ 0x110
NvRegUnknownSetupReg5 equ 0x130
NvRegUnknownSetupReg3 equ 0x13c
NvRegTxRxControl equ 0x144
NvRegMIIStatus equ 0x180
NvRegUnknownSetupReg4 equ 0x184
NvRegAdapterControl equ 0x188
NvRegMIISpeed equ 0x18c
NvRegMIIControl equ 0x190
NvRegMIIData equ 0x194
NvRegWakeUpFlags equ 0x200
NvRegPowerState equ 0x26c
NvRegPowerState2 equ 0x600
NVREG_UNKSETUP1_VAL equ 0x16070f
NVREG_UNKSETUP2_VAL equ 0x16
NVREG_UNKSETUP3_VAL1 equ 0x200010
NVREG_UNKSETUP4_VAL equ 8
NVREG_UNKSETUP5_BIT31 equ (1 shl 31)
NVREG_UNKSETUP6_VAL equ 3
NVREG_TXRXCTL_RXCHECK equ 0x0400
NVREG_MIISTAT_ERROR equ 0x0001
NVREG_MIISTAT_MASK equ 0x000f
NVREG_MIISTAT_MASK2 equ 0x000f
NVREG_MIICTL_INUSE equ 0x08000
NVREG_MIICTL_WRITE equ 0x00400
NVREG_MIICTL_ADDRSHIFT equ 5
NVREG_MIISPEED_BIT8 equ (1 shl 8)
NVREG_MIIDELAY equ 5
NVREG_IRQ_RX_ERROR equ 0x0001
NVREG_IRQ_RX equ 0x0002
NVREG_IRQ_RX_NOBUF equ 0x0004
NVREG_IRQ_LINK equ 0x0040
NVREG_IRQ_TIMER equ 0x0020
NVREG_IRQMASK_WANTED_2 equ 0x0147
NVREG_IRQ_RX_ALL equ (NVREG_IRQ_RX_ERROR or NVREG_IRQ_RX or NVREG_IRQ_RX_NOBUF)
NVREG_IRQ_TX_ALL equ 0 ; ???????????
NVREG_IRQ_OTHER_ALL equ (NVREG_IRQ_LINK or NVREG_IRQ_TIMER)
NVREG_IRQSTAT_MASK equ 0x1ff
NVREG_TXRXCTL_KICK equ 0x0001
NVREG_TXRXCTL_BIT1 equ 0x0002
NVREG_TXRXCTL_BIT2 equ 0x0004
NVREG_TXRXCTL_IDLE equ 0x0008
NVREG_TXRXCTL_RESET equ 0x0010
NVREG_TXRXCTL_RXCHECK equ 0x0400
NVREG_MCASTADDRA_FORCE equ 0x01
NVREG_MAC_RESET_ASSERT equ 0x0F3
NVREG_MISC1_HD equ 0x02
NVREG_MISC1_FORCE equ 0x3b0f3c
NVREG_PFF_ALWAYS equ 0x7F0008
NVREG_PFF_PROMISC equ 0x80
NVREG_PFF_MYADDR equ 0x20
NVREG_OFFLOAD_HOMEPHY equ 0x601
NVREG_OFFLOAD_NORMAL equ RX_NIC_BUFSIZE
NVREG_RNDSEED_MASK equ 0x00ff
NVREG_RNDSEED_FORCE equ 0x7f00
NVREG_RNDSEED_FORCE2 equ 0x2d00
NVREG_RNDSEED_FORCE3 equ 0x7400
; NVREG_POLL_DEFAULT is the interval length of the timer source on the nic
; NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
NVREG_POLL_DEFAULT equ 970
NVREG_ADAPTCTL_START equ 0x02
NVREG_ADAPTCTL_LINKUP equ 0x04
NVREG_ADAPTCTL_PHYVALID equ 0x40000
NVREG_ADAPTCTL_RUNNING equ 0x100000
NVREG_ADAPTCTL_PHYSHIFT equ 24
NVREG_WAKEUPFLAGS_VAL equ 0x7770
NVREG_POWERSTATE_POWEREDUP equ 0x8000
NVREG_POWERSTATE_VALID equ 0x0100
NVREG_POWERSTATE_MASK equ 0x0003
NVREG_POWERSTATE_D0 equ 0x0000
NVREG_POWERSTATE_D1 equ 0x0001
NVREG_POWERSTATE_D2 equ 0x0002
NVREG_POWERSTATE_D3 equ 0x0003
NVREG_POWERSTATE2_POWERUP_MASK equ 0x0F11
NVREG_POWERSTATE2_POWERUP_REV_A3 equ 0x0001
NVREG_RCVCTL_START equ 0x01
NVREG_RCVSTAT_BUSY equ 0x01
NVREG_XMITCTL_START equ 0x01
NVREG_LINKSPEED_FORCE equ 0x10000
NVREG_LINKSPEED_10 equ 1000
NVREG_LINKSPEED_100 equ 100
NVREG_LINKSPEED_1000 equ 50
NVREG_RINGSZ_TXSHIFT equ 0
NVREG_RINGSZ_RXSHIFT equ 16
LPA_1000FULL equ 0x0800
; Link partner ability register.
LPA_SLCT equ 0x001f ; Same as advertise selector
LPA_10HALF equ 0x0020 ; Can do 10mbps half-duplex
LPA_10FULL equ 0x0040 ; Can do 10mbps full-duplex
LPA_100HALF equ 0x0080 ; Can do 100mbps half-duplex
LPA_100FULL equ 0x0100 ; Can do 100mbps full-duplex
LPA_100BASE4 equ 0x0200 ; Can do 100mbps 4k packets
LPA_RESV equ 0x1c00 ; Unused...
LPA_RFAULT equ 0x2000 ; Link partner faulted
LPA_LPACK equ 0x4000 ; Link partner acked us
LPA_NPAGE equ 0x8000 ; Next page bit
MII_READ equ (-1)
MII_PHYSID1 equ 0x02 ; PHYS ID 1
MII_PHYSID2 equ 0x03 ; PHYS ID 2
MII_BMCR equ 0x00 ; Basic mode control register
MII_BMSR equ 0x01 ; Basic mode status register
MII_ADVERTISE equ 0x04 ; Advertisement control reg
MII_LPA equ 0x05 ; Link partner ability reg
MII_SREVISION equ 0x16 ; Silicon revision
MII_RESV1 equ 0x17 ; Reserved...
MII_NCONFIG equ 0x1c ; Network interface config
; PHY defines
PHY_OUI_MARVELL equ 0x5043
PHY_OUI_CICADA equ 0x03f1
PHYID1_OUI_MASK equ 0x03ff
PHYID1_OUI_SHFT equ 6
PHYID2_OUI_MASK equ 0xfc00
PHYID2_OUI_SHFT equ 10
PHY_INIT1 equ 0x0f000
PHY_INIT2 equ 0x0e00
PHY_INIT3 equ 0x01000
PHY_INIT4 equ 0x0200
PHY_INIT5 equ 0x0004
PHY_INIT6 equ 0x02000
PHY_GIGABIT equ 0x0100
PHY_TIMEOUT equ 0x1
PHY_ERROR equ 0x2
PHY_100 equ 0x1
PHY_1000 equ 0x2
PHY_HALF equ 0x100
PHY_RGMII equ 0x10000000
; desc_ver values:
; This field has two purposes:
; - Newer nics uses a different ring layout. The layout is selected by
; comparing np->desc_ver with DESC_VER_xy.
; - It contains bits that are forced on when writing to NvRegTxRxControl.
DESC_VER_1 equ 0x0
DESC_VER_2 equ (0x02100 or NVREG_TXRXCTL_RXCHECK)
MAC_ADDR_LEN equ 6
NV_TX_LASTPACKET equ (1 shl 16)
NV_TX_RETRYERROR equ (1 shl 19)
NV_TX_LASTPACKET1 equ (1 shl 24)
NV_TX_DEFERRED equ (1 shl 26)
NV_TX_CARRIERLOST equ (1 shl 27)
NV_TX_LATECOLLISION equ (1 shl 28)
NV_TX_UNDERFLOW equ (1 shl 29)
NV_TX_ERROR equ (1 shl 30)
NV_TX_VALID equ (1 shl 31)
NV_TX2_LASTPACKET equ (1 shl 29)
NV_TX2_RETRYERROR equ (1 shl 18)
NV_TX2_LASTPACKET1 equ (1 shl 23)
NV_TX2_DEFERRED equ (1 shl 25)
NV_TX2_CARRIERLOST equ (1 shl 26)
NV_TX2_LATECOLLISION equ (1 shl 27)
NV_TX2_UNDERFLOW equ (1 shl 28)
; error and valid are the same for both
NV_TX2_ERROR equ (1 shl 30)
NV_TX2_VALID equ (1 shl 31)
NV_RX_DESCRIPTORVALID equ (1 shl 16)
NV_RX_AVAIL equ (1 shl 31)
NV_RX2_DESCRIPTORVALID equ (1 shl 29)
RX_RING equ 4
TX_RING equ 2
FLAG_MASK_V1 equ 0xffff0000
FLAG_MASK_V2 equ 0xffffc000
LEN_MASK_V1 equ (0xffffffff xor FLAG_MASK_V1)
LEN_MASK_V2 equ (0xffffffff xor FLAG_MASK_V2)
; Miscelaneous hardware related defines:
NV_PCI_REGSZ_VER1 equ 0x270
NV_PCI_REGSZ_VER2 equ 0x604
; various timeout delays: all in usec
NV_TXRX_RESET_DELAY equ 4
NV_TXSTOP_DELAY1 equ 10
NV_TXSTOP_DELAY1MAX equ 500000
NV_TXSTOP_DELAY2 equ 100
NV_RXSTOP_DELAY1 equ 10
NV_RXSTOP_DELAY1MAX equ 500000
NV_RXSTOP_DELAY2 equ 100
NV_SETUP5_DELAY equ 5
NV_SETUP5_DELAYMAX equ 50000
NV_POWERUP_DELAY equ 5
NV_POWERUP_DELAYMAX equ 5000
NV_MIIBUSY_DELAY equ 50
NV_MIIPHY_DELAY equ 10
NV_MIIPHY_DELAYMAX equ 10000
NV_MAC_RESET_DELAY equ 64
NV_WAKEUPPATTERNS equ 5
NV_WAKEUPMASKENTRIES equ 4
; Advertisement control register.
ADVERTISE_SLCT equ 0x001f ; Selector bits
ADVERTISE_CSMA equ 0x0001 ; Only selector supported
ADVERTISE_10HALF equ 0x0020 ; Try for 10mbps half-duplex
ADVERTISE_10FULL equ 0x0040 ; Try for 10mbps full-duplex
ADVERTISE_100HALF equ 0x0080 ; Try for 100mbps half-duplex
ADVERTISE_100FULL equ 0x0100 ; Try for 100mbps full-duplex
ADVERTISE_100BASE4 equ 0x0200 ; Try for 100mbps 4k packets
ADVERTISE_RESV equ 0x1c00 ; Unused...
ADVERTISE_RFAULT equ 0x2000 ; Say we can detect faults
ADVERTISE_LPACK equ 0x4000 ; Ack link partners response
ADVERTISE_NPAGE equ 0x8000 ; Next page bit
ADVERTISE_FULL equ (ADVERTISE_100FULL or ADVERTISE_10FULL or ADVERTISE_CSMA)
ADVERTISE_ALL equ (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL)
MII_1000BT_CR equ 0x09
MII_1000BT_SR equ 0x0a
ADVERTISE_1000FULL equ 0x0200
ADVERTISE_1000HALF equ 0x0100
BMCR_ANRESTART equ 0x0200 ; Auto negotiation restart
BMCR_ANENABLE equ 0x1000 ; Enable auto negotiation
BMCR_SPEED100 equ 0x2000 ; Select 100Mbps
BMCR_LOOPBACK equ 0x4000 ; TXD loopback bits
BMCR_RESET equ 0x8000 ; Reset the DP83840
; Basic mode status register.
BMSR_ERCAP equ 0x0001 ; Ext-reg capability
BMSR_JCD equ 0x0002 ; Jabber detected
BMSR_LSTATUS equ 0x0004 ; Link status
BMSR_ANEGCAPABLE equ 0x0008 ; Able to do auto-negotiation
BMSR_RFAULT equ 0x0010 ; Remote fault detected
BMSR_ANEGCOMPLETE equ 0x0020 ; Auto-negotiation complete
BMSR_RESV equ 0x07c0 ; Unused...
BMSR_10HALF equ 0x0800 ; Can do 10mbps, half-duplex
BMSR_10FULL equ 0x1000 ; Can do 10mbps, full-duplex
BMSR_100HALF equ 0x2000 ; Can do 100mbps, half-duplex
BMSR_100FULL equ 0x4000 ; Can do 100mbps, full-duplex
BMSR_100BASE4 equ 0x8000 ; Can do 100mbps, 4k packets
ETH_ALEN equ 6
ETH_HLEN equ (2 * ETH_ALEN + 2)
ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for
; mininmum 64bytes frame length
uglobal
forcedeth_mmio_addr dd 0 ; memory map physical address
forcedeth_mmio_size dd 0 ; size of memory bar
forcedeth_vendor_id dw 0 ; Vendor ID
forcedeth_device_id dw 0 ; Device ID
forcedeth_orig_mac0 dd 0 ; MAC
forcedeth_orig_mac1 dd 0 ; MAC
forcedeth_mapio_addr dd 0 ; mapped IO address
forcedeth_txflags dd 0 ;
forcedeth_desc_ver dd 0 ;
forcedeth_irqmask dd 0 ; IRQ-mask
forcedeth_wolenabled dd 0 ; WOL
forcedeth_in_shutdown dd 0 ;
forcedeth_cur_rx dd 0 ;
forcedeth_refill_rx dd 0 ;
forcedeth_phyaddr dd 0 ;
forcedeth_phy_oui dd 0 ;
forcedeth_gigabit dd 0 ;
forcedeth_needs_mac_reset dd 0 ;
forcedeth_linkspeed dd 0 ;
forcedeth_duplex dd 0 ;
forcedeth_next_tx dd 0 ; next TX descriptor number
forcedeth_nic_tx dd 0 ; ??? d'nt used ???
forcedeth_packetlen dd 0 ;
forcedeth_nocable dd 0 ; no cable present
endg
struc forcedeth_TxDesc {
.PacketBuffer dd ?
.FlagLen dd ?
}
virtual at 0
forcedeth_TxDesc forcedeth_TxDesc
sizeof.forcedeth_TxDesc = $ - forcedeth_TxDesc
end virtual
struc forcedeth_RxDesc {
.PacketBuffer dd ?
.FlagLen dd ?
}
virtual at 0
forcedeth_RxDesc forcedeth_RxDesc
sizeof.forcedeth_RxDesc = $ - forcedeth_RxDesc
end virtual
virtual at eth_data_start
; Define the TX Descriptor
align 256
forcedeth_tx_ring rb TX_RING * sizeof.forcedeth_TxDesc
; Create a static buffer of size RX_BUF_SZ for each
; TX Descriptor. All descriptors point to a
; part of this buffer
align 256
forcedeth_txb rb TX_RING * RX_NIC_BUFSIZE
; Define the RX Descriptor
align 256
forcedeth_rx_ring rb RX_RING * sizeof.forcedeth_RxDesc
; Create a static buffer of size RX_BUF_SZ for each
; RX Descriptor. All descriptors point to a
; part of this buffer
align 256
forcedeth_rxb rb RX_RING * RX_NIC_BUFSIZE
end virtual
;***************************************************************************
; Function
; forcedeth_reset
; Description
; Place the chip (ie, the ethernet card) into a virgin state
; No inputs
; All registers destroyed
;
;***************************************************************************
forcedeth_reset:
; 1) erase previous misconfiguration
; 4.1-1: stop adapter: ignored, 4.3 seems to be overkill
; writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA)
mov edi, dword [forcedeth_mapio_addr]
mov dword [edi+NvRegMulticastAddrA], NVREG_MCASTADDRA_FORCE
; writel(0, base + NvRegMulticastAddrB)
mov dword [edi+NvRegMulticastAddrB], 0
; writel(0, base + NvRegMulticastMaskA)
mov dword [edi+NvRegMulticastMaskA], 0
; writel(0, base + NvRegMulticastMaskB)
mov dword [edi+NvRegMulticastMaskB], 0
; writel(0, base + NvRegPacketFilterFlags)
mov dword [edi+NvRegPacketFilterFlags], 0
; writel(0, base + NvRegTransmitterControl)
mov dword [edi+NvRegTransmitterControl], 0
; writel(0, base + NvRegReceiverControl)
mov dword [edi+NvRegReceiverControl], 0
; writel(0, base + NvRegAdapterControl)
mov dword [edi+NvRegAdapterControl], 0
; 2) initialize descriptor rings
; init_ring(nic)
call forcedeth_init_ring
; writel(0, base + NvRegLinkSpeed)
mov dword [edi+NvRegLinkSpeed], 0
; writel(0, base + NvRegUnknownTransmitterReg)
mov dword [edi+NvRegUnknownTransmitterReg], 0
; txrx_reset(nic)
call forcedeth_txrx_reset
; writel(0, base + NvRegUnknownSetupReg6)
mov dword [edi+NvRegUnknownSetupReg6], 0
; np->in_shutdown = 0
mov dword [forcedeth_in_shutdown], 0
; 3) set mac address
; writel(mac[0], base + NvRegMacAddrA)
mov eax, dword [forcedeth_orig_mac0]
mov dword [edi+NvRegMacAddrA], eax
; writel(mac[1], base + NvRegMacAddrB)
mov eax, dword [forcedeth_orig_mac1]
mov dword [edi+NvRegMacAddrB], eax
; 4) give hw rings
; writel((u32) virt_to_le32desc(&rx_ring[0]), base + NvRegRxRingPhysAddr)
mov eax, forcedeth_rx_ring
;DEBUGF 1," K : FORCEDETH: rx_ring at 0x%x\n", eax
sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov dword [edi+NvRegRxRingPhysAddr], eax
; writel((u32) virt_to_le32desc(&tx_ring[0]), base + NvRegTxRingPhysAddr)
mov eax, forcedeth_tx_ring
sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov dword [edi+NvRegTxRingPhysAddr], eax
; writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes)
mov dword [edi+NvRegRingSizes], (((RX_RING - 1) shl NVREG_RINGSZ_RXSHIFT) + ((TX_RING - 1) shl NVREG_RINGSZ_TXSHIFT))
; 5) continue setup
; np->linkspeed = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10
mov dword [forcedeth_linkspeed], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10)
; np->duplex = 0
mov dword [forcedeth_duplex], 0
; writel(np->linkspeed, base + NvRegLinkSpeed)
mov dword [edi+NvRegLinkSpeed], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10)
; writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3)
mov dword [edi+NvRegUnknownSetupReg3], NVREG_UNKSETUP3_VAL1
; writel(np->desc_ver, base + NvRegTxRxControl)
mov eax, dword [forcedeth_desc_ver]
mov dword [edi+NvRegTxRxControl], eax
; pci_push(base)
call forcedeth_pci_push
; writel(NVREG_TXRXCTL_BIT1 | np->desc_ver, base + NvRegTxRxControl)
or eax, NVREG_TXRXCTL_BIT1
mov dword [edi+NvRegTxRxControl], eax
; reg_delay(NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, "open: SetupReg5, Bit 31 remained off\n")
push ebx edx edi ;;;;;;;;;;;;;;;;;;;;;;
stdcall forcedeth_reg_delay,NvRegUnknownSetupReg5,NVREG_UNKSETUP5_BIT31,NVREG_UNKSETUP5_BIT31,NV_SETUP5_DELAY,NV_SETUP5_DELAYMAX,0
pop edi edx ebx ;;;;;;;;;;;;;;;;;;;;;;
; writel(0, base + NvRegUnknownSetupReg4)
mov dword [edi+NvRegUnknownSetupReg4], 0
; writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus)
mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK2
; printf("%d-Mbs Link, %s-Duplex\n", np->linkspeed & NVREG_LINKSPEED_10 ? 10 : 100, np->duplex ? "Full" : "Half")
;;;;;;;;;;; DEBUGF
; 6) continue setup
; writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1)
mov dword [edi+NvRegMisc1], (NVREG_MISC1_FORCE or NVREG_MISC1_HD)
; writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus)
mov eax, dword [edi+NvRegTransmitterStatus]
mov dword [edi+NvRegTransmitterStatus], eax
; writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags)
mov dword [edi+NvRegPacketFilterFlags], NVREG_PFF_ALWAYS
; writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig)
mov dword [edi+NvRegOffloadConfig], NVREG_OFFLOAD_NORMAL
; writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus)
mov eax, dword [edi+NvRegReceiverStatus]
mov dword [edi+NvRegReceiverStatus], eax
; Get a random number
; i = random()
push edi
stdcall sys_clock ; eax = 0x00SSMMHH (current system time)
pop edi
; writel(NVREG_RNDSEED_FORCE | (i & NVREG_RNDSEED_MASK), base + NvRegRandomSeed)
and eax, NVREG_RNDSEED_MASK
or eax, NVREG_RNDSEED_FORCE
mov dword [edi+NvRegRandomSeed], eax
; writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1)
mov dword [edi+NvRegUnknownSetupReg1], NVREG_UNKSETUP1_VAL
; writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2)
mov dword [edi+NvRegUnknownSetupReg2], NVREG_UNKSETUP2_VAL
; writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval)
mov dword [edi+NvRegPollingInterval], NVREG_POLL_DEFAULT
; writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6)
mov dword [edi+NvRegUnknownSetupReg6], NVREG_UNKSETUP6_VAL
; writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT) | NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING,
; base + NvRegAdapterControl)
mov eax, dword [forcedeth_phyaddr]
shl eax, NVREG_ADAPTCTL_PHYSHIFT
or eax, (NVREG_ADAPTCTL_PHYVALID or NVREG_ADAPTCTL_RUNNING)
mov dword [edi+NvRegAdapterControl], eax
; writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed)
mov dword [edi+NvRegMIISpeed], (NVREG_MIISPEED_BIT8 or NVREG_MIIDELAY)
; writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4)
mov dword [edi+NvRegUnknownSetupReg4], NVREG_UNKSETUP4_VAL
; writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags)
mov dword [edi+NvRegWakeUpFlags], NVREG_WAKEUPFLAGS_VAL
; i = readl(base + NvRegPowerState)
mov eax, dword [edi+NvRegPowerState]
; if ((i & NVREG_POWERSTATE_POWEREDUP) == 0)
test eax, NVREG_POWERSTATE_POWEREDUP
jnz @f
; writel(NVREG_POWERSTATE_POWEREDUP | i, base + NvRegPowerState)
or eax, NVREG_POWERSTATE_POWEREDUP
mov dword [edi+NvRegPowerState], eax
@@:
; pci_push(base)
call forcedeth_pci_push
; nv_udelay(10)
mov esi, 10
call forcedeth_nv_udelay
; writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState)
mov eax, dword [edi+NvRegPowerState]
or eax, NVREG_POWERSTATE_VALID
mov dword [edi+NvRegPowerState], eax
; ??? disable all interrupts ???
; writel(0, base + NvRegIrqMask)
mov dword [edi+NvRegIrqMask], 0
;;; ; ??? Mask RX interrupts
;;; mov dword [edi+NvRegIrqMask], NVREG_IRQ_RX_ALL
;;; ; ??? Mask TX interrupts
;;; ;mov dword [edi+NvRegIrqMask], NVREG_IRQ_TX_ALL
;;; ; ??? Mask OTHER interrupts
;;; mov dword [edi+NvRegIrqMask], NVREG_IRQ_OTHER_ALL
; pci_push(base)
call forcedeth_pci_push
; writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus)
mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK2
; writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus)
mov dword [edi+NvRegIrqStatus], NVREG_IRQSTAT_MASK
; pci_push(base)
call forcedeth_pci_push
; writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA)
mov dword [edi+NvRegMulticastAddrA], NVREG_MCASTADDRA_FORCE
; writel(0, base + NvRegMulticastAddrB)
mov dword [edi+NvRegMulticastAddrB], 0
; writel(0, base + NvRegMulticastMaskA)
mov dword [edi+NvRegMulticastMaskA], 0
; writel(0, base + NvRegMulticastMaskB)
mov dword [edi+NvRegMulticastMaskB], 0
; writel(NVREG_PFF_ALWAYS | NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags)
mov dword [edi+NvRegPacketFilterFlags], (NVREG_PFF_ALWAYS or NVREG_PFF_MYADDR)
; set_multicast(nic)
call forcedeth_set_multicast
; One manual link speed update: Interrupts are enabled, future link
; speed changes cause interrupts and are handled by nv_link_irq().
; miistat = readl(base + NvRegMIIStatus)
mov eax, dword [edi+NvRegMIIStatus]
; writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK
; dprintf(("startup: got 0x%hX.\n", miistat));
;;; DEBUGF 1," K : FORCEDETH: startup: got 0x%x\n", eax
; ret = update_linkspeed(nic)
call forcedeth_update_linkspeed
push eax
; start_tx(nic)
call forcedeth_start_tx
pop eax
; if (ret) {
; //Start Connection netif_carrier_on(dev);
; } else {
; printf("no link during initialization.\n");
; }
;*** added by shurf (21.09.2008)
mov dword [forcedeth_nocable], 0
;***
test eax, eax
jnz .return
DEBUGF 1," K : FORCEDETH: no link during initialization.\n"
;*** added by shurf (21.09.2008)
mov dword [forcedeth_nocable], 1
;***
.return:
; Indicate that we have successfully reset the card
mov eax, dword [pci_data]
mov dword [eth_status], eax
ret
;***************************************************************************
; Function
; forcedeth_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
;
;***************************************************************************
forcedeth_probe:
; DEBUGF 1," K : FORCEDETH: 0x%x 0x%x, 0x%x\n", [io_addr]:8,[pci_bus]:2,[pci_dev]:2
mov dword [forcedeth_needs_mac_reset], 0
; BEGIN of adjust_pci_device()
; read word from PCI-device
mov al, 1 ;;;;;;;;;;;;;;2
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_REG_COMMAND
call pci_read_reg
mov bx, ax ; new command
or bx, PCI_COMMAND_MASTER
or bx, PCI_COMMAND_IO
cmp bx, ax
je @f
; Enabling PCI-device (make card as bus master)
DEBUGF 1," K : FORCEDETH: Updating PCI command 0x%x->0x%x\n", ax, bx
mov cx, bx
mov al, 1 ;;;;;;;;;;;;2
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_REG_COMMAND
call pci_write_reg
; Check latency settings
@@:
; Get current latency settings from Latency timer register (byte)
mov al, 0 ;;;;;;;;;1
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_LATENCY_TIMER
call pci_read_reg
; see if its at least 32
cmp al, 32
jge @f
; set latency to 32
DEBUGF 1, "K : FORCEDETH: PCI latency timer (CFLT) is unreasonably low at %d.\n", al
DEBUGF 1, "K : FORCEDETH: Setting to 32 clocks.\n"
mov cl, 32
mov al, 0 ;;;;;;;1
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_LATENCY_TIMER
call pci_write_reg
; END of adjust_pci_device()
@@:
; BEGIN of pci_bar_start (addr = pci_bar_start(pci, PCI_BASE_ADDRESS_0))
mov al, 2 ; dword
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_BASE_ADDRESS_0
call pci_read_reg
test eax, PCI_BASE_ADDRESS_SPACE_IO
jz @f
and eax, PCI_BASE_ADDRESS_IO_MASK
jmp .next
@@: push eax
and eax, PCI_BASE_ADDRESS_MEM_TYPE_MASK
cmp eax, PCI_BASE_ADDRESS_MEM_TYPE_64
jne .not64
mov al, 2 ; dword
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_BASE_ADDRESS_0 + 4
call pci_read_reg
or eax, eax
jz .not64
DEBUGF 1,"K : FORCEDETH: pci_bar_start: Unhandled 64bit BAR\n"
or eax, -1
jmp .next
.not64:
pop eax
and eax, PCI_BASE_ADDRESS_MEM_MASK
.next:
; END of pci_bar_start
; addr = eax
mov dword [forcedeth_mmio_addr], eax
; BEGIN of pci_bar_size (sz = pci_bar_size(pci, PCI_BASE_ADDRESS_0))
; Save original bar
mov al, 2 ; dword
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_BASE_ADDRESS_0
call pci_read_reg
mov dword [forcedeth_tmp_start], eax
; Compute which bits can be set
; (ecx - value to write)
mov al, 2 ; dword
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_BASE_ADDRESS_0
mov ecx, (not 0)
call pci_write_reg
mov al, 2 ; dword
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_BASE_ADDRESS_0
call pci_read_reg
push eax
; Restore the original size
mov al, 2 ; dword
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_BASE_ADDRESS_0
mov ecx, dword [forcedeth_tmp_start]
call pci_write_reg
; Find the significant bits
pop eax
test dword [forcedeth_tmp_start], PCI_BASE_ADDRESS_SPACE_IO
jz @f
and eax, PCI_BASE_ADDRESS_IO_MASK
jmp .next2
@@: and eax, PCI_BASE_ADDRESS_MEM_MASK
.next2:
; Find the lowest bit set
mov ecx, eax
sub eax, 1
not eax
and ecx, eax
; END of pci_bar_start
mov dword [forcedeth_mmio_size], ecx
DEBUGF 1," K : FORCEDETH: mmio_addr= 0x%x [mmio_size= 0x%x]\n", [forcedeth_mmio_addr]:8, [forcedeth_mmio_size]:8
; Get Vendor and Device ID
mov al, 2
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_VENDOR_ID
call pci_read_reg
mov word [forcedeth_vendor_id], ax
shr eax, 16
mov word [forcedeth_device_id], ax
DEBUGF 1," K : FORCEDETH: vendor_id= 0x%x device_id= 0x%x\n", [forcedeth_vendor_id]:4, [forcedeth_device_id]:4
; handle different descriptor versions
mov eax, dword [forcedeth_device_id]
cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_1
je .ver1
cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_2
je .ver1
cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_3
je .ver1
mov dword [forcedeth_desc_ver], DESC_VER_2
jmp @f
.ver1: mov dword [forcedeth_desc_ver], DESC_VER_1
@@:
; read the mac address
; map memory
stdcall map_io_mem, [forcedeth_mmio_addr], [forcedeth_mmio_size], (PG_SW+PG_NOCACHE)
test eax, eax
jz .fail
mov dword [forcedeth_mapio_addr], eax
mov edi, eax
mov eax, dword [edi+NvRegMacAddrA]
mov dword [forcedeth_orig_mac0], eax
mov eax, dword [edi+NvRegMacAddrB]
mov dword [forcedeth_orig_mac1], eax
; save MAC-address to global variable node_addr
mov ecx, MAC_ADDR_LEN
xor ebx, ebx
mov edx, forcedeth_orig_mac0
add edx, (MAC_ADDR_LEN-1)
@@: mov al, byte [edx]
mov byte [node_addr+ebx], al
inc ebx
dec edx
loop @b
; DEBUGF 1," K : FORCEDETH: orig_mac0= 0x%x\n", [forcedeth_orig_mac0]:8
; DEBUGF 1," K : FORCEDETH: orig_mac1= 0x%x\n", [forcedeth_orig_mac1]:8
DEBUGF 1," K : FORCEDETH: MAC = %x-%x-%x-%x-%x-%x\n", [node_addr+0]:2,[node_addr+1]:2,[node_addr+2]:2,[node_addr+3]:2,[node_addr+4]:2,[node_addr+5]:2,
; disable WOL
mov edi, dword [forcedeth_mapio_addr]
mov dword [edi+NvRegWakeUpFlags], 0
mov dword [forcedeth_wolenabled], 0
mov dword [forcedeth_txflags], (NV_TX2_LASTPACKET or NV_TX2_VALID)
cmp dword [forcedeth_desc_ver], DESC_VER_1
jne @f
mov dword [forcedeth_txflags], (NV_TX_LASTPACKET or NV_TX_VALID)
@@:
; BEGIN of switch (pci->dev_id)
cmp word [forcedeth_device_id], 0x01C3
jne .next_0x0066
; nforce
mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER)
jmp .end_switch
.next_0x0066:
cmp word [forcedeth_device_id], 0x0066
je @f
cmp word [forcedeth_device_id], 0x00D6
je @f
jmp .next_0x0086
@@:
mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER)
cmp dword [forcedeth_desc_ver], DESC_VER_1
jne @f
or dword [forcedeth_txflags], NV_TX_LASTPACKET1
jmp .end_switch
@@: or dword [forcedeth_txflags], NV_TX2_LASTPACKET1
jmp .end_switch
.next_0x0086:
cmp word [forcedeth_device_id], 0x0086
je @f
cmp word [forcedeth_device_id], 0x008c
je @f
cmp word [forcedeth_device_id], 0x00e6
je @f
cmp word [forcedeth_device_id], 0x00df
je @f
cmp word [forcedeth_device_id], 0x0056
je @f
cmp word [forcedeth_device_id], 0x0057
je @f
cmp word [forcedeth_device_id], 0x0037
je @f
cmp word [forcedeth_device_id], 0x0038
je @f
jmp .next_0x0268
@@:
; np->irqmask = NVREG_IRQMASK_WANTED_2;
; np->irqmask |= NVREG_IRQ_TIMER;
mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER)
; if (np->desc_ver == DESC_VER_1)
cmp dword [forcedeth_desc_ver], DESC_VER_1
jne @f
; np->tx_flags |= NV_TX_LASTPACKET1;
or dword [forcedeth_txflags], NV_TX_LASTPACKET1
jmp .end_switch
; else
@@:
; np->tx_flags |= NV_TX2_LASTPACKET1;
or dword [forcedeth_txflags], NV_TX2_LASTPACKET1
; break;
jmp .end_switch
.next_0x0268:
cmp word [forcedeth_device_id], 0x0268
je @f
cmp word [forcedeth_device_id], 0x0269
je @f
cmp word [forcedeth_device_id], 0x0372
je @f
cmp word [forcedeth_device_id], 0x0373
je @f
jmp .default_switch
@@:
; pci_read_config_byte(pci, PCI_REVISION_ID, &revision_id);
mov al, 0 ; byte
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, PCI_REVISION_ID
call pci_read_reg
mov ecx, eax ; cl = revision_id
; take phy and nic out of low power mode
; powerstate = readl(base + NvRegPowerState2);
mov edi, dword [forcedeth_mapio_addr]
mov eax, dword [edi+NvRegPowerState2] ; eax = powerstate
; powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK;
and eax, not NVREG_POWERSTATE2_POWERUP_MASK
; if ((pci->dev_id==PCI_DEVICE_ID_NVIDIA_NVENET_12||pci->dev_id==PCI_DEVICE_ID_NVIDIA_NVENET_13)&&revision_id>=0xA3)
cmp dword [forcedeth_device_id], PCI_DEVICE_ID_NVIDIA_NVENET_12
je @f
cmp dword [forcedeth_device_id], PCI_DEVICE_ID_NVIDIA_NVENET_13
je @f
jmp .end_if
@@:
cmp cl, 0xA3
jl .end_if
; powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3;
or eax, NVREG_POWERSTATE2_POWERUP_REV_A3
.end_if:
; writel(powerstate, base + NvRegPowerState2);
mov dword [edi+NvRegPowerState2], eax
; //DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ
; np->irqmask = NVREG_IRQMASK_WANTED_2;
; np->irqmask |= NVREG_IRQ_TIMER;
mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER)
; needs_mac_reset = 1;
mov dword [forcedeth_needs_mac_reset], 1
; if (np->desc_ver == DESC_VER_1)
cmp dword [forcedeth_desc_ver], DESC_VER_1
jne @f
; np->tx_flags |= NV_TX_LASTPACKET1;
or dword [forcedeth_txflags], NV_TX_LASTPACKET1
jmp .end_if2
@@:
; else
; np->tx_flags |= NV_TX2_LASTPACKET1;
or dword [forcedeth_txflags], NV_TX2_LASTPACKET1
.end_if2:
; break;
jmp .end_switch
.default_switch:
DEBUGF 1," K : FORCEDETH: Your card was undefined in this driver.\n"
DEBUGF 1," K : FORCEDETH: Review driver_data in Kolibri driver and send a patch\n"
.end_switch:
; END of switch (pci->dev_id)
; Find a suitable phy
mov dword [forcedeth_tmp_i], 1
.for_loop:
; for (i = 1; i <= 32; i++)
; phyaddr = i & 0x1f
mov ebx, dword [forcedeth_tmp_i]
and ebx, 0x1f
; id1 = mii_rw(phyaddr, MII_PHYSID1, MII_READ)
;EBX - addr, EAX - miireg, ECX - value
mov eax, MII_PHYSID1
mov ecx, MII_READ
call forcedeth_mii_rw ; id1 = eax
; if (id1 < 0 || id1 == 0xffff)
cmp eax, 0xffffffff
je .continue_for
test eax, 0x80000000
jnz .continue_for
mov dword [forcedeth_tmp_id1], eax
; id2 = mii_rw(nic, phyaddr, MII_PHYSID2, MII_READ)
mov eax, MII_PHYSID2
mov ecx, MII_READ
call forcedeth_mii_rw ; id2 = eax
; if (id2 < 0 || id2 == 0xffff)
cmp eax, 0xffffffff
je .continue_for
test eax, 0x80000000
jnz .continue_for
mov dword [forcedeth_tmp_id2], eax
jmp .break_for
.continue_for:
inc dword [forcedeth_tmp_i]
cmp dword [forcedeth_tmp_i], 32
jle .for_loop
jmp .end_for
.break_for:
;;;; DEBUGF 1," K : FORCEDETH: id1=0x%x id2=0x%x\n", [forcedeth_tmp_id1]:8, [forcedeth_tmp_id2]:8
; id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT
mov eax, dword [forcedeth_tmp_id1]
and eax, PHYID1_OUI_MASK
shl eax, PHYID1_OUI_SHFT
mov dword [forcedeth_tmp_id1], eax
; id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT
mov eax, dword [forcedeth_tmp_id2]
and eax, PHYID2_OUI_MASK
shr eax, PHYID2_OUI_SHFT
mov dword [forcedeth_tmp_id2], eax
DEBUGF 1," K : FORCEDETH: Found PHY 0x%x:0x%x at address 0x%x\n", [forcedeth_tmp_id1]:8, [forcedeth_tmp_id2]:8, ebx
; np->phyaddr = phyaddr;
mov dword [forcedeth_phyaddr], ebx
; np->phy_oui = id1 | id2;
mov eax, dword [forcedeth_tmp_id1]
or eax, dword [forcedeth_tmp_id2]
mov dword [forcedeth_phy_oui], eax
.end_for:
; if (i == 33)
cmp dword [forcedeth_tmp_i], 33
jne @f
; PHY in isolate mode? No phy attached and user wants to
; test loopback? Very odd, but can be correct.
DEBUGF 1," K : FORCEDETH: Could not find a valid PHY.\n"
jmp .next3
@@:
; if (i != 33)
; reset it
call forcedeth_phy_init
.next3:
; dprintf(("%s: forcedeth.c: subsystem: %hX:%hX bound to %s\n",
; pci->name, pci->vendor, pci->dev_id, pci->name));
DEBUGF 1," K : FORCEDETH: subsystem: 0x%x:0x%x bound to forcedeth\n", [forcedeth_vendor_id]:4, [forcedeth_device_id]:4
; if(needs_mac_reset) mac_reset(nic);
cmp dword [forcedeth_needs_mac_reset], 0
je @f
call forcedeth_mac_reset
@@:
; if(!forcedeth_reset(nic)) return 0; // no valid link
call forcedeth_reset
test eax, eax
jnz @f
mov eax, 0
jmp .return
@@:
; point to NIC specific routines
; dev->disable = forcedeth_disable;
; nic->poll = forcedeth_poll;
; nic->transmit = forcedeth_transmit;
; nic->irq = forcedeth_irq;
;;;;;;;;;stdcall attach_int_handler, 11, forcedeth_int_handler, 0
; return 1
mov eax, 1
jmp .return
.fail:
mov eax, 0
.return:
ret
uglobal
forcedeth_tmp_start dd ?
forcedeth_tmp_reg dd ?
forcedeth_tmp_i dd ?
forcedeth_tmp_id1 dd ?
forcedeth_tmp_id2 dd ?
forcedeth_tmp_phyinterface dd ?
forcedeth_tmp_newls dd ?
forcedeth_tmp_newdup dd ?
forcedeth_tmp_retval dd ?
forcedeth_tmp_control_1000 dd ?
forcedeth_tmp_lpa dd ?
forcedeth_tmp_adv dd ?
forcedeth_tmp_len dd ?
forcedeth_tmp_valid dd ?
forcedeth_tmp_nr dd ?
forcedeth_tmp_ptxb dd ?
endg
;***************************************************************************
; Function
; forcedeth_poll
;
; Description
; Polls the ethernet card for a received packet
; Received data, if any, ends up in Ether_buffer
;
;***************************************************************************
forcedeth_poll:
mov word [eth_rx_data_len], 0
; ????????????????????????????
; ??? Clear events? ???
mov edi, dword [forcedeth_mapio_addr]
mov dword [edi+NvRegIrqStatus], NVREG_IRQSTAT_MASK
; ????????????????????????????
.top:
; i = np->cur_rx % RX_RING
mov eax, dword [forcedeth_cur_rx]
and eax, (RX_RING-1)
mov dword [forcedeth_tmp_i], eax
; Flags = le32_to_cpu(rx_ring[i].FlagLen)
; Flags = rx_ring[i].FlagLen
mov cl, sizeof.forcedeth_RxDesc
mul cl
add eax, forcedeth_rx_ring
mov ebx, eax
mov eax, [ebx + forcedeth_RxDesc.FlagLen]
; if (Flags & NV_RX_AVAIL)
test eax, NV_RX_AVAIL
; return 0; /* still owned by hardware, */
; still owned by hardware
jnz .return0
;;;;; DEBUGF 1,"poll: FlagLen = %x\n", eax
; if (np->desc_ver == DESC_VER_1) {
cmp dword [forcedeth_desc_ver], DESC_VER_1
jne @f
; if (!(Flags & NV_RX_DESCRIPTORVALID))
test eax, NV_RX_DESCRIPTORVALID
; return 0;
jz .return0
jmp .next
; } else {
@@:
; if (!(Flags & NV_RX2_DESCRIPTORVALID))
test eax, NV_RX2_DESCRIPTORVALID
; return 0;
jz .return0
; }
.next:
; len = nv_descr_getlength(&rx_ring[i], np->desc_ver)
; len = rx_ring[i].FlagLen & ((np->desc_ver == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
; eax = FlagLen
cmp dword [forcedeth_desc_ver], DESC_VER_1
jne @f
and eax, LEN_MASK_V1
jmp .next2
@@:
and eax, LEN_MASK_V2
.next2:
; mov dword [forcedeth_tmp_len], eax
; valid = 1
mov dword [forcedeth_tmp_valid], 1
; got a valid packet - forward it to the network core
; nic->packetlen = len;
mov dword [forcedeth_packetlen], eax
;
mov word [eth_rx_data_len], ax
;;;;;;;;; DEBUGF 1,"poll: packet len = 0x%x\n", [forcedeth_packetlen]
; memcpy(nic->packet, rxb + (i * RX_NIC_BUFSIZE), nic->packetlen);
; Copy packet to system buffer (Ether_buffer)
;???? ecx = (len-4)
mov ecx, eax
push ecx
shr ecx, 2
; rxb + (i * RX_NIC_BUFSIZE)
mov eax, dword [forcedeth_tmp_i]
mov bx, RX_NIC_BUFSIZE
mul bx
add eax, forcedeth_rxb
mov esi, eax
mov edi, Ether_buffer
cld ; set to increment
rep movsd ; mov dword from [esi++] to [edi++]
pop ecx
and ecx, 3 ; copy rest 1-3 bytes
rep movsb
; wmb();
; ???
; np->cur_rx++;
inc dword [forcedeth_cur_rx]
; if (!valid)
cmp dword [forcedeth_tmp_valid], 0
jne @f
; goto top;
jmp .top
@@:
; alloc_rx(nic);
call forcedeth_alloc_rx
; return 1;
jmp .return1
;;;;; DEBUGF 1,"K : FORCEDETH: poll: ...\n"
.return0:
mov eax, 0
jmp .return
.return1:
mov eax, 1
.return:
;;push eax
; ????????????????????????????????????????????????
; ????? clear interrupt mask/status
; read IRQ status
;;mov edi, dword [forcedeth_mapio_addr]
;;mov eax, dword [edi+NvRegIrqStatus]
; clear events
;;and eax, not (NVREG_IRQ_RX_ERROR or NVREG_IRQ_RX or NVREG_IRQ_RX_NOBUF or NVREG_IRQ_LINK or NVREG_IRQ_TIMER)
; write IRQ status
;;mov dword [edi+NvRegIrqStatus], eax
; ????????????????????????????????????????????????
;;pop eax
ret
;***************************************************************************
; Function
; forcedeth_transmit
;
; Description
; Transmits a packet of data via the ethernet card
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
;
;***************************************************************************
forcedeth_transmit:
; send the packet to destination
;pusha
;DEBUGF 1,"K : FORCEDETH: transmit: packet type = 0x%x\n", ebx
;DEBUGF 1,"K : FORCEDETH: transmit: packet len = 0x%x\n", ecx
;mov eax, dword [edi]
;DEBUGF 1,"K : FORCEDETH: transmit: dest adr = 0x%x\n", eax
;mov eax, dword [edi+4]
;DEBUGF 1,"K : FORCEDETH: transmit: dest adr2 = 0x%x\n", eax
;mov eax, dword [node_addr]
;DEBUGF 1,"K : FORCEDETH: transmit: src adr = 0x%x\n", eax
;mov eax, dword [node_addr+4]
;DEBUGF 1,"K : FORCEDETH: transmit: src adr2 = 0x%x\n", eax
;popa
; int nr = np->next_tx % TX_RING
mov eax, dword [forcedeth_next_tx]
and eax, (TX_RING-1)
mov dword [forcedeth_tmp_nr], eax
; point to the current txb incase multiple tx_rings are used
; ptxb = txb + (nr * RX_NIC_BUFSIZE)
push ecx
mov cx, RX_NIC_BUFSIZE
mul cx ; AX*CX, result to DX:AX
add eax, forcedeth_txb
mov dword [forcedeth_tmp_ptxb], eax
push esi
mov esi, edi ; dst MAC
mov edi, eax ; packet buffer
cld ; set to increment
; copy the packet to ring buffer
; memcpy(ptxb, d, ETH_ALEN); /* dst */
movsd
movsw
; memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
mov esi, node_addr
movsd
movsw
; nstype = htons((u16) t); /* type */
; memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); /* type */
mov word [edi], bx
add edi, 2
; memcpy(ptxb + ETH_HLEN, p, s);
pop esi
pop ecx
push ecx
shr ecx, 2 ; count in dwords
rep movsd ; copy dwords from [esi+=4] to [edi+=4]
pop ecx
push ecx
and ecx, 3 ; copy rest 1-3 bytes
rep movsb ; copy bytess from [esi++] to [edi++]
; s += ETH_HLEN;
; while (s < ETH_ZLEN) /* pad to min length */
; ptxb[s++] = '\0';
; pad to min length
pop ecx
add ecx, ETH_HLEN
push ecx ; header length + data length
cmp ecx, ETH_ZLEN
jge @f
mov eax, ETH_ZLEN
sub eax, ecx
xchg eax, ecx
mov al, 0
rep stosb ; copy byte from al to [edi++]
@@:
; tx_ring[nr].PacketBuffer = (u32) virt_to_le32desc(ptxb);
mov eax, dword [forcedeth_tmp_nr]
mov cl, sizeof.forcedeth_TxDesc
mul cl
add eax, forcedeth_tx_ring
mov ebx, eax
mov eax, dword [forcedeth_tmp_ptxb]
sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov [ebx + forcedeth_TxDesc.PacketBuffer], eax
;DEBUGF 1,"K : FORCEDETH: transmit: PacketBuffer = 0x%x\n", eax
;DEBUGF 1,"K : FORCEDETH: transmit: txflags = 0x%x\n", [forcedeth_txflags]:8
; wmb();
; tx_ring[nr].FlagLen = cpu_to_le32((s - 1) | np->tx_flags);
pop eax ; header length + data length
mov ecx, dword [forcedeth_txflags]
or eax, ecx
mov [ebx + forcedeth_TxDesc.FlagLen], eax
; writel(NVREG_TXRXCTL_KICK | np->desc_ver, base + NvRegTxRxControl);
mov edi, dword [forcedeth_mapio_addr]
mov eax, dword [forcedeth_desc_ver]
or eax, NVREG_TXRXCTL_KICK
mov dword [edi+NvRegTxRxControl], eax
; pci_push(base);
call forcedeth_pci_push
; np->next_tx++
inc dword [forcedeth_next_tx] ; may be need to reset? Overflow?
ret
;***************************************************************************
; Function
; forcedeth_cable
;
; Description
; Return AL=0, if cable is not connected
; Returm AL=1, if cable is connected
;
;***************************************************************************
forcedeth_cable:
mov al, 1
cmp dword [forcedeth_nocable], 1
jne .return
mov al, 0
.return:
ret
;***************************************************************************
; read/write a register on the PHY.
; Caller must guarantee serialization
; Input: EAX - miireg, EBX - addr, ECX - value
; Output: EAX - retval
forcedeth_mii_rw:
push ebx
push eax ; save miireg
; writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus)
mov edi, dword [forcedeth_mapio_addr]
mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK
; reg = readl(base + NvRegMIIControl)
mov eax, dword [edi+NvRegMIIControl]
test eax, NVREG_MIICTL_INUSE
jz @f
; writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl)
mov dword [edi+NvRegMIIControl], NVREG_MIICTL_INUSE
; nv_udelay(NV_MIIBUSY_DELAY)
mov esi, NV_MIIBUSY_DELAY
call forcedeth_nv_udelay
@@:
; reg = (addr << NVREG_MIICTL_ADDRSHIFT) | miireg
pop edx ; restore miireg
mov eax, ebx
shl eax, NVREG_MIICTL_ADDRSHIFT
or eax, edx
mov dword [forcedeth_tmp_reg], eax
cmp ecx, MII_READ
je @f
; writel(value, base + NvRegMIIData)
mov dword [edi+NvRegMIIData], ecx
; reg |= NVREG_MIICTL_WRITE
or dword [forcedeth_tmp_reg], NVREG_MIICTL_WRITE
@@:
; writel(reg, base + NvRegMIIControl)
mov eax, dword [forcedeth_tmp_reg]
mov dword [edi+NvRegMIIControl], eax
push ebx edx edi ;;;;;;;;;;;;;;;;;;;;;;
; reg_delay(NvRegMIIControl, NVREG_MIICTL_INUSE, 0, NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL)
stdcall forcedeth_reg_delay,NvRegMIIControl,NVREG_MIICTL_INUSE,0,NV_MIIPHY_DELAY,NV_MIIPHY_DELAYMAX,0
pop edi edx ebx ;;;;;;;;;;;;;;;;;;;;;;
test eax, eax
jz @f
;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw of reg %d at PHY %d timed out.\n", edx, ebx
mov eax, 0xffffffff
jmp .return
@@:
cmp ecx, MII_READ
je @f
;it was a write operation - fewer failures are detectable
;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw wrote 0x%x to reg %d at PHY %d\n", ecx, edx, ebx
mov eax, 0
jmp .return
@@:
; readl(base + NvRegMIIStatus)
mov eax, dword [edi+NvRegMIIStatus]
test eax, NVREG_MIISTAT_ERROR
jz @f
;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw of reg %d at PHY %d failed.\n", edx, ebx
mov eax, 0xffffffff
jmp .return
@@:
; retval = readl(base + NvRegMIIData)
mov eax, dword [edi+NvRegMIIData]
;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw read from reg %d at PHY %d: 0x%x.\n", edx, ebx, eax
.return:
pop ebx
ret
; Input: ESI - delay
; Output: none
forcedeth_nv_udelay:
push ebx
cmp dword [forcedeth_in_shutdown], 0
jne @f
call forcedeth_udelay ; delay on ESI
jmp .return
@@:
.loop:
cmp esi, 0
je .return
; Don't allow an rx_ring overflow to happen
; while shutting down the NIC it will
; kill the receive function.
call forcedeth_drop_rx
mov ebx, 3 ; sleep = 3
cmp ebx, esi ; if(sleep > delay)
jle @f
mov ebx, esi ; sleep = delay
@@:
push esi
mov esi, ebx
; udelay(sleep)
call forcedeth_udelay ; delay on ESI
pop esi
sub esi, ebx ; delay -= sleep
jmp .loop
.return:
pop ebx
ret
; Input: none
; Output: none
forcedeth_drop_rx:
push eax ebx ecx edi
; events = readl(base + NvRegIrqStatus)
mov edi, dword [forcedeth_mapio_addr]
mov eax, dword [edi+NvRegIrqStatus]
test eax, eax
jz @f
; writel(events, base + NvRegIrqStatus)
mov dword [edi+NvRegIrqStatus], eax
@@:
;if (!(events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)))
test eax, (NVREG_IRQ_RX_ERROR or NVREG_IRQ_RX or NVREG_IRQ_RX_NOBUF)
jz .return
.loop:
; i = np->cur_rx % RX_RING
mov eax, dword [forcedeth_cur_rx]
and eax, (RX_RING-1)
; //Flags = le32_to_cpu(rx_ring[i].FlagLen)
; Flags = rx_ring[i].FlagLen
mov cl, sizeof.forcedeth_RxDesc
mul cl
add eax, forcedeth_rx_ring
mov ebx, eax
mov eax, [ebx + forcedeth_RxDesc.FlagLen]
; len = nv_descr_getlength(&rx_ring[i], np->desc_ver)
; > len = Flags & ((np->desc_ver == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2)
; ??? len don't used later !!! ???
; ...
test eax, NV_RX_AVAIL
jnz .return ; still owned by hardware,
; wmb()
; ??? may be empty function ???
; np->cur_rx++
inc dword [forcedeth_cur_rx]
; alloc_rx(NULL)
call forcedeth_alloc_rx
.return:
pop edi ecx ebx eax
ret
; Fill rx ring entries.
; Return 1 if the allocations for the skbs failed and the
; rx engine is without Available descriptors
; Input: none
; Output: none
forcedeth_alloc_rx:
push eax ebx ecx edx
; refill_rx = np->refill_rx
mov ecx, dword [forcedeth_refill_rx]
.loop:
cmp dword [forcedeth_cur_rx], ecx
je .loop_end
; nr = refill_rx % RX_RING
mov eax, ecx
and eax, (RX_RING-1) ; nr
; rx_ring[nr].PacketBuffer = &rxb[nr * RX_NIC_BUFSIZE]
push ecx
push eax
mov cl, sizeof.forcedeth_RxDesc
mul cl
add eax, forcedeth_rx_ring
mov ebx, eax
pop eax
mov cx, RX_NIC_BUFSIZE
mul cx
pop ecx
add eax, forcedeth_rxb
sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov [ebx + forcedeth_RxDesc.PacketBuffer], eax
; wmb()
; ...
; rx_ring[nr].FlagLen = RX_NIC_BUFSIZE | NV_RX_AVAIL
mov [ebx + forcedeth_RxDesc.FlagLen], (RX_NIC_BUFSIZE or NV_RX_AVAIL)
inc ecx
jmp .loop
.loop_end:
; np->refill_rx = refill_rx
mov [forcedeth_refill_rx], ecx
.return:
pop edx ecx ebx eax
ret
; Delay in millisec
; Input: ESI - delay in ms
; Output: none
forcedeth_udelay:
call delay_ms
ret
; Input: offset:word, mask:dword, target:dword, delay:word, delaymax:word, msg:dword
; Output: EAX - 0|1
;;;;proc forcedeth_reg_delay,offset:word,mask:dword,target:dword,delay:word,delaymax:word,msg:dword
proc forcedeth_reg_delay,offset:dword,mask:dword,target:dword,delay:dword,delaymax:dword,msg:dword
push ebx esi edi
; pci_push(base)
call forcedeth_pci_push
.loop:
; nv_udelay(delay)
mov esi, dword [delay]
call forcedeth_nv_udelay ; delay in esi
mov eax, dword [delaymax]
sub eax, dword [delay]
mov dword [delaymax], eax
; if (delaymax < 0)
test dword [delaymax], 0x80000000
jz @f
; return 1
mov eax, 1
jmp .return
@@:
; while ((readl(base + offset) & mask) != target)
mov edi, dword [forcedeth_mapio_addr]
mov ebx, dword [offset]
mov eax, dword [edi+ebx]
and eax, dword [mask]
cmp eax, dword [target]
jne .loop
xor eax, eax
.return:
pop edi esi ebx
ret
endp
; Input: none
; Output: none
forcedeth_pci_push:
push eax edi
;force out pending posted writes
mov edi, dword [forcedeth_mapio_addr]
mov eax, dword [edi]
pop edi eax
ret
; Input: none
; Output: EAX - result (0 = OK, other = error)
forcedeth_phy_init:
push ebx ecx
; set advertise register
; reg = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ);
; EBX - addr, EAX - miireg, ECX - value
mov ebx, dword [forcedeth_phyaddr]
mov eax, MII_ADVERTISE
mov ecx, MII_READ
call forcedeth_mii_rw ; reg = eax
; reg |=
; (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF |
; ADVERTISE_100FULL | 0x800 | 0x400);
or eax, (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL or 0x800 or 0x400)
; if (mii_rw(nic, np->phyaddr, MII_ADVERTISE, reg))
; EBX - addr, EAX - miireg, ECX - value
mov ecx, eax ; reg
mov eax, MII_ADVERTISE
call forcedeth_mii_rw ; eax -> return
test eax, eax
jz @f
; printf("phy write to advertise failed.\n");
DEBUGF 1," K : FORCEDETH: phy write to advertise failed.\n"
; return PHY_ERROR;
mov eax, PHY_ERROR
jmp .return
@@:
; get phy interface type
; phyinterface = readl(base + NvRegPhyInterface);
mov edi, dword [forcedeth_mapio_addr]
mov eax, dword [edi+NvRegPhyInterface] ; phyinterface = eax
mov dword [forcedeth_tmp_phyinterface], eax
;;;;;;;;;;;;;;;;;;;;;;;;;
DEBUGF 1," K : FORCEDETH: phy interface type = 0x%x\n", [forcedeth_tmp_phyinterface]:8
;;;;;;;;;;;;;;;;;;;;;;;;;
; see if gigabit phy
; mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
; EBX - addr, EAX - miireg, ECX - value
mov eax, MII_BMSR
mov ecx, MII_READ
call forcedeth_mii_rw ; mii_status = eax
; if (mii_status & PHY_GIGABIT)
test eax, PHY_GIGABIT
jnz .gigabit
; np->gigabit = 0;
mov dword [forcedeth_gigabit], 0
jmp .next_if
.gigabit:
; np->gigabit = PHY_GIGABIT;
mov dword [forcedeth_gigabit], PHY_GIGABIT
; mii_control_1000 = mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ);
; EBX - addr, EAX - miireg, ECX - value
mov eax, MII_1000BT_CR
mov ecx, MII_READ
call forcedeth_mii_rw ; mii_control_1000 = eax
; mii_control_1000 &= ~ADVERTISE_1000HALF;
and eax, (not ADVERTISE_1000HALF)
; if (phyinterface & PHY_RGMII)
test dword [forcedeth_tmp_phyinterface], PHY_RGMII
jz @f
; mii_control_1000 |= ADVERTISE_1000FULL
or eax, ADVERTISE_1000FULL
jmp .next
@@:
; mii_control_1000 &= ~ADVERTISE_1000FULL
and eax, (not ADVERTISE_1000FULL)
.next:
; if (mii_rw(nic, np->phyaddr, MII_1000BT_CR, mii_control_1000))
; EBX - addr, EAX - miireg, ECX - value
mov ecx, eax
mov eax, MII_1000BT_CR
call forcedeth_mii_rw ; eax -> return
test eax, eax
jz .next_if
; printf("phy init failed.\n");
DEBUGF 1," K : FORCEDETH: phy init failed.\n"
; return PHY_ERROR;
mov eax, PHY_ERROR
jmp .return
.next_if:
; reset the phy
; if (phy_reset(nic))
call forcedeth_phy_reset
test eax, eax
jz @f
; printf("phy reset failed\n")
DEBUGF 1," K : FORCEDETH: phy reset failed.\n"
; return PHY_ERROR
mov eax, PHY_ERROR
jmp .return
@@:
; phy vendor specific configuration
; if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII))
cmp dword [forcedeth_phy_oui], PHY_OUI_CICADA
jne .next_if2
test dword [forcedeth_tmp_phyinterface], PHY_RGMII
jz .next_if2
; phy_reserved = mii_rw(nic, np->phyaddr, MII_RESV1, MII_READ)
; EBX - addr, EAX - miireg, ECX - value
mov eax, MII_RESV1
mov ecx, MII_READ
call forcedeth_mii_rw ; phy_reserved = eax
; phy_reserved &= ~(PHY_INIT1 | PHY_INIT2)
and eax, (not (PHY_INIT1 or PHY_INIT2))
; phy_reserved |= (PHY_INIT3 | PHY_INIT4)
or eax, (PHY_INIT3 or PHY_INIT4)
; if (mii_rw(nic, np->phyaddr, MII_RESV1, phy_reserved))
; EBX - addr, EAX - miireg, ECX - value
mov ecx, eax
mov eax, MII_RESV1
call forcedeth_mii_rw ; eax -> return
test eax, eax
jz @f
; printf("phy init failed.\n")
DEBUGF 1," K : FORCEDETH: phy init failed.\n"
; return PHY_ERROR
mov eax, PHY_ERROR
jmp .return
@@:
; phy_reserved = mii_rw(nic, np->phyaddr, MII_NCONFIG, MII_READ);
; EBX - addr, EAX - miireg, ECX - value
mov eax, MII_NCONFIG
mov ecx, MII_READ
call forcedeth_mii_rw ; phy_reserved = eax
; phy_reserved |= PHY_INIT5
or eax, PHY_INIT5
; if (mii_rw(nic, np->phyaddr, MII_NCONFIG, phy_reserved))
; EBX - addr, EAX - miireg, ECX - value
mov ecx, eax
mov eax, MII_NCONFIG
call forcedeth_mii_rw ; eax -> return
test eax, eax
jz .next_if2
; printf("phy init failed.\n")
DEBUGF 1," K : FORCEDETH: phy init failed.\n"
; return PHY_ERROR
mov eax, PHY_ERROR
jmp .return
.next_if2:
; if (np->phy_oui == PHY_OUI_CICADA)
cmp dword [forcedeth_phy_oui], PHY_OUI_CICADA
jne .restart
; phy_reserved = mii_rw(nic, np->phyaddr, MII_SREVISION, MII_READ)
; EBX - addr, EAX - miireg, ECX - value
mov eax, MII_SREVISION
mov ecx, MII_READ
call forcedeth_mii_rw ; phy_reserved = eax
; phy_reserved |= PHY_INIT6
or eax, PHY_INIT6
; if (mii_rw(nic, np->phyaddr, MII_SREVISION, phy_reserved))
mov ecx, eax
mov eax, MII_SREVISION
call forcedeth_mii_rw ; eax -> return
test eax, eax
jz .restart
; printf("phy init failed.\n");
DEBUGF 1," K : FORCEDETH: phy init failed.\n"
; return PHY_ERROR;
jmp .return
.restart:
; restart auto negotiation
; mii_control = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ)
; EBX - addr, EAX - miireg, ECX - value
mov eax, MII_BMCR
mov ecx, MII_READ
call forcedeth_mii_rw ; mii_control = eax
; mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE)
or eax, (BMCR_ANRESTART or BMCR_ANENABLE)
; if (mii_rw(nic, np->phyaddr, MII_BMCR, mii_control))
mov ecx, eax
mov eax, MII_BMCR
call forcedeth_mii_rw ; eax -> return
test eax, eax
jz .ok
; return PHY_ERROR;
mov eax, PHY_ERROR
jmp .return
.ok:
mov eax, 0
.return:
pop ecx ebx
ret
; Input: none
; Output: EAX - result (0 = OK, other = error)
forcedeth_phy_reset:
push ebx ecx edx
; miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
; EBX - addr, EAX - miireg, ECX - value
mov ebx, dword [forcedeth_phyaddr]
mov eax, MII_BMCR
mov ecx, MII_READ
call forcedeth_mii_rw ; miicontrol = eax
; miicontrol |= BMCR_RESET;
or eax, BMCR_RESET
push eax
; if (mii_rw(nic, np->phyaddr, MII_BMCR, miicontrol))
; EBX - addr, EAX - miireg, ECX - value
mov ecx, eax
mov eax, MII_BMCR
call forcedeth_mii_rw ; miicontrol = eax
test eax, eax
jz @f
pop eax
mov eax, 0xffffffff
jmp .return
@@:
pop eax
; wait for 500ms
; mdelay(500)
mov esi, 500
call forcedeth_udelay
; must wait till reset is deasserted
; while (miicontrol & BMCR_RESET) {
mov edx, 100
.while_loop:
test eax, BMCR_RESET
jz .while_loop_exit
; mdelay(10);
mov esi, 10
call forcedeth_udelay
; miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
; EBX - addr, EAX - miireg, ECX - value
mov eax, MII_BMCR
mov ecx, MII_READ
call forcedeth_mii_rw ; miicontrol = eax
; FIXME: 100 tries seem excessive
; if (tries++ > 100)
dec edx
jnz .while_loop
; return -1;
mov eax, 0xffffffff
jmp .return
.while_loop_exit:
; return 0
mov eax, 0
.return:
pop edx ecx ebx
ret
; Input: none
; Output: none
forcedeth_mac_reset:
push esi edi
; dprintf("mac_reset\n")
DEBUGF 1," K : FORCEDETH: mac_reset.\n"
; writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl)
mov edi, dword [forcedeth_mapio_addr]
mov eax, dword [forcedeth_desc_ver]
or eax, (NVREG_TXRXCTL_BIT2 or NVREG_TXRXCTL_RESET)
mov dword [edi+NvRegTxRxControl], eax
; pci_push(base)
call forcedeth_pci_push
; writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset)
mov dword [edi+NvRegMacReset], NVREG_MAC_RESET_ASSERT
; pci_push(base)
call forcedeth_pci_push
; udelay(NV_MAC_RESET_DELAY)
mov esi, NV_MAC_RESET_DELAY
call forcedeth_nv_udelay
; writel(0, base + NvRegMacReset)
mov dword [edi+NvRegMacReset], 0
; pci_push(base)
call forcedeth_pci_push
; udelay(NV_MAC_RESET_DELAY)
mov esi, NV_MAC_RESET_DELAY
call forcedeth_nv_udelay
; writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl)
mov eax, dword [forcedeth_desc_ver]
or eax, NVREG_TXRXCTL_BIT2
mov dword [edi+NvRegTxRxControl], eax
; pci_push(base)
call forcedeth_pci_push
pop edi esi
ret
; Input: none
; Output: none
forcedeth_init_ring:
push eax ebx ecx
; np->next_tx = np->nic_tx = 0
mov dword[forcedeth_next_tx], 0
mov dword[forcedeth_nic_tx], 0
; for (i = 0; i < TX_RING; i++)
mov ecx, TX_RING
.for_loop:
; tx_ring[i].FlagLen = 0;
mov eax, ecx
dec eax
mov bl, sizeof.forcedeth_TxDesc
mul bl
add eax, forcedeth_tx_ring
mov ebx, eax
mov dword [ebx + forcedeth_TxDesc.FlagLen], 0
loop .for_loop
; np->cur_rx = RX_RING;
mov dword [forcedeth_cur_rx], RX_RING
; np->refill_rx = 0;
mov dword [forcedeth_refill_rx], 0
;for (i = 0; i < RX_RING; i++)
mov ecx, RX_RING
.for_loop2:
; rx_ring[i].FlagLen = 0;
mov eax, ecx
dec eax
mov bl, sizeof.forcedeth_RxDesc
mul bl
add eax, forcedeth_rx_ring
mov ebx, eax
mov dword [ebx + forcedeth_RxDesc.FlagLen], 0
loop .for_loop2
; alloc_rx(nic);
call forcedeth_alloc_rx
.return:
pop ecx ebx eax
ret
; Input: none
; Output: none
forcedeth_txrx_reset:
push eax esi edi
; dprintf(("txrx_reset\n"))
DEBUGF 1," K : FORCEDETH: txrx_reset.\n"
; writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl)
mov edi, dword [forcedeth_mapio_addr]
mov eax, dword [forcedeth_desc_ver]
or eax, (NVREG_TXRXCTL_BIT2 or NVREG_TXRXCTL_RESET)
mov dword [edi+NvRegTxRxControl], eax
; pci_push(base)
call forcedeth_pci_push
; nv_udelay(NV_TXRX_RESET_DELAY)
mov esi, NV_TXRX_RESET_DELAY
call forcedeth_nv_udelay
; writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl)
mov eax, dword [forcedeth_desc_ver]
or eax, NVREG_TXRXCTL_BIT2
mov dword [edi+NvRegTxRxControl], eax
; pci_push(base)
call forcedeth_pci_push
.return:
pop edi esi eax
ret
; Input: none
; Output: none
forcedeth_set_multicast:
push edi
; u32 addr[2];
; u32 mask[2];
; u32 pff;
; u32 alwaysOff[2];
; u32 alwaysOn[2];
;
; memset(addr, 0, sizeof(addr));
; memset(mask, 0, sizeof(mask));
;
; pff = NVREG_PFF_MYADDR;
;
; alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0;
;
; addr[0] = alwaysOn[0];
; addr[1] = alwaysOn[1];
; mask[0] = alwaysOn[0] | alwaysOff[0];
; mask[1] = alwaysOn[1] | alwaysOff[1];
;
; addr[0] |= NVREG_MCASTADDRA_FORCE;
; pff |= NVREG_PFF_ALWAYS;
; stop_rx();
call forcedeth_stop_rx
; writel(addr[0], base + NvRegMulticastAddrA);
mov edi, dword [forcedeth_mapio_addr]
mov dword [edi+NvRegMulticastAddrA], NVREG_MCASTADDRA_FORCE
; writel(addr[1], base + NvRegMulticastAddrB);
mov dword [edi+NvRegMulticastAddrB], 0
; writel(mask[0], base + NvRegMulticastMaskA);
mov dword [edi+NvRegMulticastMaskA], 0
; writel(mask[1], base + NvRegMulticastMaskB);
mov dword [edi+NvRegMulticastMaskB], 0
; writel(pff, base + NvRegPacketFilterFlags);
mov dword [edi+NvRegPacketFilterFlags], (NVREG_PFF_MYADDR or NVREG_PFF_ALWAYS)
; start_rx(nic);
call forcedeth_start_rx
.return:
pop edi
ret
; Input: none
; Output: none
forcedeth_start_rx:
push edi
; dprintf(("start_rx\n"))
DEBUGF 1," K : FORCEDETH: start_rx.\n"
; Already running? Stop it.
; if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
mov edi, dword [forcedeth_mapio_addr]
mov eax, dword [edi+NvRegReceiverControl]
test eax, NVREG_RCVCTL_START
jz @f
; writel(0, base + NvRegReceiverControl)
mov dword [edi+NvRegReceiverControl], 0
; pci_push(base)
call forcedeth_pci_push
@@:
; writel(np->linkspeed, base + NvRegLinkSpeed);
mov eax, dword [forcedeth_linkspeed]
mov dword [edi+NvRegLinkSpeed], eax
; pci_push(base);
call forcedeth_pci_push
; writel(NVREG_RCVCTL_START, base + NvRegReceiverControl);
mov dword [edi+NvRegReceiverControl], NVREG_RCVCTL_START
; pci_push(base);
call forcedeth_pci_push
.return:
pop edi
ret
; Input: none
; Output: none
forcedeth_stop_rx:
push esi edi
; dprintf(("stop_rx\n"))
DEBUGF 1," K : FORCEDETH: stop_rx.\n"
; writel(0, base + NvRegReceiverControl)
mov edi, dword [forcedeth_mapio_addr]
mov dword [edi+NvRegReceiverControl], 0
push ebx edx edi ;;;;;;;;;;;;;;;;;;;;;;
; reg_delay(NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, "stop_rx: ReceiverStatus remained busy");
stdcall forcedeth_reg_delay,NvRegReceiverStatus,NVREG_RCVSTAT_BUSY,0,NV_RXSTOP_DELAY1,NV_RXSTOP_DELAY1MAX,0
pop edi edx ebx ;;;;;;;;;;;;;;;;;;;;;;
; nv_udelay(NV_RXSTOP_DELAY2)
mov esi, NV_RXSTOP_DELAY2
call forcedeth_nv_udelay
; writel(0, base + NvRegLinkSpeed)
mov dword [edi+NvRegLinkSpeed], 0
.return:
pop edi esi
ret
; Input: none
; Output: EAX
forcedeth_update_linkspeed:
push ebx ecx esi edi
; BMSR_LSTATUS is latched, read it twice:
; we want the current value.
; mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ)
;EBX - addr, EAX - miireg, ECX - value
mov ebx, dword [forcedeth_phyaddr]
mov eax, MII_BMSR
mov ecx, MII_READ
call forcedeth_mii_rw
; mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ)
;EBX - addr, EAX - miireg, ECX - value
mov ebx, dword [forcedeth_phyaddr]
mov eax, MII_BMSR
mov ecx, MII_READ
call forcedeth_mii_rw ; mii_status = eax
; yhlu
; for(i=0;i<30;i++) {
mov ecx, 30
.for_loop:
push ecx
; mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
;EBX - addr, EAX - miireg, ECX - value
;mov ebx, dword [forcedeth_phyaddr]
mov eax, MII_BMSR
mov ecx, MII_READ
call forcedeth_mii_rw ; mii_status = eax
; if((mii_status & BMSR_LSTATUS) && (mii_status & BMSR_ANEGCOMPLETE)) break;
test eax, BMSR_LSTATUS
jz @f
test eax, BMSR_ANEGCOMPLETE
jz @f
; break
pop ecx
jmp .break
@@:
; mdelay(100);
push eax ; ???
mov esi, 100
call forcedeth_udelay
pop eax ; ???
pop ecx
loop .for_loop
.break:
; if (!(mii_status & BMSR_LSTATUS)) {
test eax, BMSR_LSTATUS
jnz @f
; printf("no link detected by phy - falling back to 10HD.\n")
DEBUGF 1," K : FORCEDETH: update_linkspeed: no link detected by phy - falling back to 10HD.\n"
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10)
; newdup = 0;
mov dword [forcedeth_tmp_newdup], 0
; retval = 0;
mov dword [forcedeth_tmp_retval], 0
; goto set_speed;
jmp .set_speed
@@:
; check auto negotiation is complete
; if (!(mii_status & BMSR_ANEGCOMPLETE)) {
test eax, BMSR_ANEGCOMPLETE
jnz @f
; still in autonegotiation - configure nic for 10 MBit HD and wait.
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10)
; newdup = 0
mov dword [forcedeth_tmp_newdup], 0
; retval = 0
mov dword [forcedeth_tmp_retval], 0
; printf("autoneg not completed - falling back to 10HD.\n")
DEBUGF 1," K : FORCEDETH: update_linkspeed: autoneg not completed - falling back to 10HD.\n"
; goto set_speed
jmp .set_speed
@@:
; retval = 1
mov dword [forcedeth_tmp_retval], 1
; if (np->gigabit == PHY_GIGABIT) {
cmp dword [forcedeth_gigabit], PHY_GIGABIT
jne .end_if
; control_1000 = mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ)
;EBX - addr, EAX - miireg, ECX - value
;mov ebx, dword [forcedeth_phyaddr]
mov eax, MII_1000BT_CR
mov ecx, MII_READ
call forcedeth_mii_rw ; control_1000 = eax
mov dword [forcedeth_tmp_control_1000], eax
; status_1000 = mii_rw(nic, np->phyaddr, MII_1000BT_SR, MII_READ)
;EBX - addr, EAX - miireg, ECX - value
;mov ebx, dword [forcedeth_phyaddr]
mov eax, MII_1000BT_SR
mov ecx, MII_READ
call forcedeth_mii_rw ; status_1000 = eax
;mov dword [forcedeth_tmp_status_1000], eax
; if ((control_1000 & ADVERTISE_1000FULL) &&
; (status_1000 & LPA_1000FULL)) {
test eax, LPA_1000FULL
jz .end_if
test dword [forcedeth_tmp_control_1000], ADVERTISE_1000FULL
jz .end_if
; printf ("update_linkspeed: GBit ethernet detected.\n")
DEBUGF 1," K : FORCEDETH: update_linkspeed: GBit ethernet detected.\n"
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_1000
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_1000)
; newdup = 1
mov dword [forcedeth_tmp_newdup], 1
; goto set_speed
jmp .set_speed
.end_if:
; adv = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ);
;EBX - addr, EAX - miireg, ECX - value
;mov ebx, dword [forcedeth_phyaddr]
mov eax, MII_ADVERTISE
mov ecx, MII_READ
call forcedeth_mii_rw ; adv = eax
mov dword [forcedeth_tmp_adv], eax
; lpa = mii_rw(nic, np->phyaddr, MII_LPA, MII_READ);
;EBX - addr, EAX - miireg, ECX - value
;mov ebx, dword [forcedeth_phyaddr]
mov eax, MII_LPA
mov ecx, MII_READ
call forcedeth_mii_rw ; lpa = eax
mov dword [forcedeth_tmp_lpa], eax
; dprintf(("update_linkspeed: PHY advertises 0x%hX, lpa 0x%hX.\n", adv, lpa));
DEBUGF 1," K : FORCEDETH: update_linkspeed: PHY advertises 0x%x, lpa 0x%x.\n", [forcedeth_tmp_adv]:8, [forcedeth_tmp_lpa]:8
; FIXME: handle parallel detection properly, handle gigabit ethernet
; lpa = lpa & adv
mov eax, dword [forcedeth_tmp_adv]
and dword [forcedeth_tmp_lpa], eax
mov eax, dword [forcedeth_tmp_lpa]
; if (lpa & LPA_100FULL) {
test eax, LPA_100FULL
jz @f
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_100)
; newdup = 1
mov dword [forcedeth_tmp_newdup], 1
jmp .set_speed
@@:
; } else if (lpa & LPA_100HALF) {
test eax, LPA_100HALF
jz @f
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_100)
; newdup = 0
mov dword [forcedeth_tmp_newdup], 0
jmp .set_speed
@@:
; } else if (lpa & LPA_10FULL) {
test eax, LPA_10FULL
jz @f
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10)
; newdup = 1
mov dword [forcedeth_tmp_newdup], 1
jmp .set_speed
@@:
; } else if (lpa & LPA_10HALF) {
test eax, LPA_10HALF
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10)
; newdup = 0;
mov dword [forcedeth_tmp_newdup], 0
jmp .set_speed
@@:
; } else {
; printf("bad ability %hX - falling back to 10HD.\n", lpa)
DEBUGF 1," K : FORCEDETH: update_linkspeed: bad ability 0x%x - falling back to 10HD.\n", eax
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10)
; newdup = 0
mov dword [forcedeth_tmp_newdup], 0
; }
.set_speed:
; if (np->duplex == newdup && np->linkspeed == newls)
mov eax, dword [forcedeth_tmp_newdup]
cmp eax, dword [forcedeth_duplex]
jne .end_if2
mov eax, dword [forcedeth_tmp_newls]
cmp eax, dword [forcedeth_linkspeed]
jne .end_if2
; return retval;
jmp .return
.end_if2:
; dprintf(("changing link setting from %d/%s to %d/%s.\n",
; np->linkspeed, np->duplex ? "Full-Duplex": "Half-Duplex", newls, newdup ? "Full-Duplex": "Half-Duplex"))
DEBUGF 1," K : FORCEDETH: update_linkspeed: changing link from %x/XD to %x/XD.\n", [forcedeth_linkspeed]:8, [forcedeth_tmp_newls]:8 ; !!!!!!!!!!!!!!!!!!!!!!!!!!!!
; np->duplex = newdup
mov eax, dword [forcedeth_tmp_newdup]
mov dword [forcedeth_duplex], eax
; np->linkspeed = newls
mov eax, [forcedeth_tmp_newls]
mov dword [forcedeth_linkspeed], eax
; if (np->gigabit == PHY_GIGABIT) {
cmp dword [forcedeth_gigabit], PHY_GIGABIT
jne .end_if3
; phyreg = readl(base + NvRegRandomSeed);
mov edi, dword [forcedeth_mapio_addr]
mov eax, dword [edi+NvRegRandomSeed]
; phyreg &= ~(0x3FF00);
and eax, not (0x3FF00)
mov ecx, eax ; phyreg = ecx
; if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10)
mov eax, dword [forcedeth_linkspeed]
and eax, 0xFFF
cmp eax, NVREG_LINKSPEED_10
jne @f
; phyreg |= NVREG_RNDSEED_FORCE3
or ecx, NVREG_RNDSEED_FORCE3
jmp .end_if4
@@:
; else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
cmp eax, NVREG_LINKSPEED_100
jne @f
; phyreg |= NVREG_RNDSEED_FORCE2
or ecx, NVREG_RNDSEED_FORCE2
jmp .end_if4
@@:
; else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
cmp eax, NVREG_LINKSPEED_1000
jne .end_if4
; phyreg |= NVREG_RNDSEED_FORCE
or ecx, NVREG_RNDSEED_FORCE
.end_if4:
; writel(phyreg, base + NvRegRandomSeed)
mov dword [edi+NvRegRandomSeed], ecx
.end_if3:
; phyreg = readl(base + NvRegPhyInterface)
mov ecx, dword [edi+NvRegPhyInterface]
; phyreg &= ~(PHY_HALF | PHY_100 | PHY_1000)
and ecx, not (PHY_HALF or PHY_100 or PHY_1000)
; if (np->duplex == 0)
cmp dword [forcedeth_duplex], 0
jne @f
; phyreg |= PHY_HALF
or ecx, PHY_HALF
@@:
; if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
mov eax, dword [forcedeth_linkspeed]
and eax, 0xFFF
cmp eax, NVREG_LINKSPEED_100
jne @f
; phyreg |= PHY_100
or ecx, PHY_100
jmp .end_if5
@@:
; else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
cmp eax, NVREG_LINKSPEED_1000
jne .end_if5
; phyreg |= PHY_1000
or ecx, PHY_1000
.end_if5:
; writel(phyreg, base + NvRegPhyInterface)
mov dword [edi+NvRegPhyInterface], ecx
; writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD), base + NvRegMisc1);
cmp dword [forcedeth_duplex], 0
je @f
mov ecx, 0
jmp .next
@@:
mov ecx, NVREG_MISC1_HD
.next:
or ecx, NVREG_MISC1_FORCE
mov dword [edi+NvRegMisc1], ecx
; pci_push(base)
call forcedeth_pci_push
; writel(np->linkspeed, base + NvRegLinkSpeed)
mov eax, dword [forcedeth_linkspeed]
mov dword [edi+NvRegLinkSpeed], eax
; pci_push(base)
call forcedeth_pci_push
.return:
; return retval
mov eax, dword [forcedeth_tmp_retval]
pop edi esi ecx ebx
ret
; Input: none
; Output: none
forcedeth_start_tx:
push edi
; dprintf(("start_tx\n"))
DEBUGF 1," K : FORCEDETH: start_tx.\n"
; writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl)
mov edi, dword [forcedeth_mapio_addr]
mov dword [edi+NvRegTransmitterControl], NVREG_XMITCTL_START
; pci_push(base)
call forcedeth_pci_push
.return:
pop edi
ret
; Interrupt handler
forcedeth_int_handler:
DEBUGF 1," K : FORCEDETH: interrupt handler.\n"
ret