373d7e9391
git-svn-id: svn://kolibrios.org@1194 a494cfbc-eb01-0410-851d-a64ba20cac60
2693 lines
70 KiB
PHP
2693 lines
70 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; 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 edx, dword [edi+NvRegMacAddrB]
|
|
mov dword [forcedeth_orig_mac1], edx
|
|
|
|
; save MAC-address to global variable node_addr
|
|
mov dword [node_addr], eax
|
|
mov word [node_addr+4], dx
|
|
|
|
; reverse if desired
|
|
cmp word [forcedeth_device_id], 0x03E5
|
|
jae .no_reverse_mac
|
|
mov al, byte [node_addr]
|
|
xchg al, byte [node_addr+5]
|
|
mov byte [node_addr], al
|
|
mov al, byte [node_addr+1]
|
|
xchg al, byte [node_addr+4]
|
|
mov byte [node_addr+4], al
|
|
mov al, byte [node_addr+2]
|
|
xchg al, byte [node_addr+3]
|
|
mov byte [node_addr+3], al
|
|
.no_reverse_mac:
|
|
|
|
; 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
|
|
;@@:
|
|
cmp word [forcedeth_device_id], 0x0268
|
|
jb .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
|
|
|