From 23f7fb6f1c02c2e6a15dcf6c51987dd610e11dd0 Mon Sep 17 00:00:00 2001 From: "Dmitry Kartashov (shurf)" Date: Tue, 23 Sep 2008 23:03:34 +0000 Subject: [PATCH] FORCEDETH network driver git-svn-id: svn://kolibrios.org@866 a494cfbc-eb01-0410-851d-a64ba20cac60 --- .../network/eth_drv/drivers/forcedeth.inc | 2683 +++++++++++++++++ kernel/trunk/network/eth_drv/ethernet.inc | 3 + 2 files changed, 2686 insertions(+) create mode 100644 kernel/trunk/network/eth_drv/drivers/forcedeth.inc diff --git a/kernel/trunk/network/eth_drv/drivers/forcedeth.inc b/kernel/trunk/network/eth_drv/drivers/forcedeth.inc new file mode 100644 index 0000000000..fad665d023 --- /dev/null +++ b/kernel/trunk/network/eth_drv/drivers/forcedeth.inc @@ -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 + diff --git a/kernel/trunk/network/eth_drv/ethernet.inc b/kernel/trunk/network/eth_drv/ethernet.inc index b296f2ff7b..72c8e2b8ca 100644 --- a/kernel/trunk/network/eth_drv/ethernet.inc +++ b/kernel/trunk/network/eth_drv/ethernet.inc @@ -104,6 +104,7 @@ include "drivers/3c59x.inc" include "drivers/sis900.inc" include "drivers/pcnet32.inc" include "drivers/rtl8169.inc" +include "drivers/forcedeth.inc" ; PCICards ; ======== @@ -200,6 +201,8 @@ dd 0x70161039, SIS900_probe, SIS900_reset, SIS900_poll, SIS900_transmit, 0 ;dd 0x08001516, mtd80x_probe, mtd80x_reset, mtd80x_poll, mtd80x_transmit, mtd80x_cable ;dd 0x08911516, mtd80x_probe, mtd80x_reset, mtd80x_poll, mtd80x_transmit, mtd80x_cable +dd 0x006610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, 0 ; nVidia Corporation nForce2 Ethernet Controller + rb PCICARDS_ENTRY_SIZE ; end of list marker, do not remove endg