0,0 → 1,2683 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; 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 |
|