summaryrefslogtreecommitdiff
path: root/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c
diff options
context:
space:
mode:
authorbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
committerbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
commit878ddf1fc3540a715f63594ed22b6929e881afb4 (patch)
treec56c44dac138137b510e1fba7c3efe5e4d84bea2 /EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c
downloadedk2-878ddf1fc3540a715f63594ed22b6929e881afb4.zip
edk2-878ddf1fc3540a715f63594ed22b6929e881afb4.tar.gz
edk2-878ddf1fc3540a715f63594ed22b6929e881afb4.tar.bz2
Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c')
-rw-r--r--EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c3772
1 files changed, 3772 insertions, 0 deletions
diff --git a/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c
new file mode 100644
index 0000000..5b69a46
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c
@@ -0,0 +1,3772 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+
+ E100B.C
+
+Abstract:
+
+
+Revision History
+
+--*/
+
+#include "undi32.h"
+
+static UINT8 basic_config_cmd[22] = {
+ 22, 0x08,
+ 0, 0,
+ 0, (UINT8)0x80,
+ 0x32, 0x03,
+ 1, 0,
+ 0x2E, 0,
+ 0x60, 0,
+ (UINT8)0xf2, 0x48,
+ 0, 0x40,
+ (UINT8)0xf2, (UINT8)0x80, // 0x40=Force full-duplex
+ 0x3f, 0x05,
+};
+
+//
+// How to wait for the command unit to accept a command.
+// Typically this takes 0 ticks.
+//
+#define wait_for_cmd_done(cmd_ioaddr) \
+{ \
+ INT16 wait = 2000; \
+ while ((InByte (AdapterInfo, cmd_ioaddr) != 0) && --wait >= 0) \
+ DelayIt (AdapterInfo, 10); \
+ if (wait == 0) \
+ DelayIt (AdapterInfo, 50); \
+}
+
+UINT8
+InByte (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to read a byte from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ Port - Which port to read from.
+
+Returns:
+ Results - The data read from the port.
+
+--*/
+// TODO: AdapterInfo - add argument and description to function comment
+{
+ UINT8 Results;
+
+ (*AdapterInfo->Mem_Io) (
+ AdapterInfo->Unique_ID,
+ PXE_MEM_READ,
+ 1,
+ (UINT64)Port,
+ (UINT64) (UINTN) &Results
+ );
+ return Results;
+}
+
+UINT16
+InWord (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to read a word from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ Port - Which port to read from.
+
+Returns:
+ Results - The data read from the port.
+
+--*/
+// TODO: AdapterInfo - add argument and description to function comment
+{
+ UINT16 Results;
+
+ (*AdapterInfo->Mem_Io) (
+ AdapterInfo->Unique_ID,
+ PXE_MEM_READ,
+ 2,
+ (UINT64)Port,
+ (UINT64)(UINTN)&Results
+ );
+ return Results;
+}
+
+UINT32
+InLong (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to read a dword from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ Port - Which port to read from.
+
+Returns:
+ Results - The data read from the port.
+
+--*/
+// TODO: AdapterInfo - add argument and description to function comment
+{
+ UINT32 Results;
+
+ (*AdapterInfo->Mem_Io) (
+ AdapterInfo->Unique_ID,
+ PXE_MEM_READ,
+ 4,
+ (UINT64)Port,
+ (UINT64)(UINTN)&Results
+ );
+ return Results;
+}
+
+VOID
+OutByte (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT8 Data,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to write a byte from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ Data - Data to write to Port.
+ Port - Which port to write to.
+
+Returns:
+ none
+
+--*/
+// TODO: AdapterInfo - add argument and description to function comment
+{
+ UINT8 Val;
+
+ Val = Data;
+ (*AdapterInfo->Mem_Io) (
+ AdapterInfo->Unique_ID,
+ PXE_MEM_WRITE,
+ 1,
+ (UINT64)Port,
+ (UINT64)(UINTN)(UINTN)&Val
+ );
+ return ;
+}
+
+VOID
+OutWord (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT16 Data,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to write a word from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ Data - Data to write to Port.
+ Port - Which port to write to.
+
+Returns:
+ none
+
+--*/
+// TODO: AdapterInfo - add argument and description to function comment
+{
+ UINT16 Val;
+
+ Val = Data;
+ (*AdapterInfo->Mem_Io) (
+ AdapterInfo->Unique_ID,
+ PXE_MEM_WRITE,
+ 2,
+ (UINT64)Port,
+ (UINT64)(UINTN)&Val
+ );
+ return ;
+}
+
+VOID
+OutLong (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT32 Data,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to write a dword from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ Data - Data to write to Port.
+ Port - Which port to write to.
+
+Returns:
+ none
+
+--*/
+// TODO: AdapterInfo - add argument and description to function comment
+{
+ UINT32 Val;
+
+ Val = Data;
+ (*AdapterInfo->Mem_Io) (
+ AdapterInfo->Unique_ID,
+ PXE_MEM_WRITE,
+ 4,
+ (UINT64)Port,
+ (UINT64)(UINTN)&Val
+ );
+ return ;
+}
+
+UINTN
+MapIt (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT64 MemAddr,
+ IN UINT32 Size,
+ IN UINT32 Direction,
+ OUT UINT64 MappedAddr
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ MemAddr - TODO: add argument description
+ Size - TODO: add argument description
+ Direction - TODO: add argument description
+ MappedAddr - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ UINT64 *PhyAddr;
+
+ PhyAddr = (UINT64 *) (UINTN) MappedAddr;
+ //
+ // mapping is different for theold and new NII protocols
+ //
+ if (AdapterInfo->VersionFlag == 0x30) {
+ if (AdapterInfo->Virt2Phys_30 == (VOID *) NULL) {
+ *PhyAddr = (UINT64) AdapterInfo->MemoryPtr;
+ } else {
+ (*AdapterInfo->Virt2Phys_30) (MemAddr, (UINT64) (UINTN) PhyAddr);
+ }
+
+ if (*PhyAddr > FOUR_GIGABYTE) {
+ return PXE_STATCODE_INVALID_PARAMETER;
+ }
+ } else {
+ if (AdapterInfo->Map_Mem == (VOID *) NULL) {
+ //
+ // this UNDI cannot handle addresses beyond 4 GB without a map routine
+ //
+ if (MemAddr > FOUR_GIGABYTE) {
+ return PXE_STATCODE_INVALID_PARAMETER;
+ } else {
+ *PhyAddr = MemAddr;
+ }
+ } else {
+ (*AdapterInfo->Map_Mem) (
+ AdapterInfo->Unique_ID,
+ MemAddr,
+ Size,
+ Direction,
+ MappedAddr
+ );
+ }
+ }
+
+ return PXE_STATCODE_SUCCESS;
+}
+
+VOID
+UnMapIt (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT64 MemAddr,
+ IN UINT32 Size,
+ IN UINT32 Direction,
+ IN UINT64 MappedAddr
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ MemAddr - TODO: add argument description
+ Size - TODO: add argument description
+ Direction - TODO: add argument description
+ MappedAddr - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ if (AdapterInfo->VersionFlag > 0x30) {
+ //
+ // no mapping service
+ //
+ if (AdapterInfo->UnMap_Mem != (VOID *) NULL) {
+ (*AdapterInfo->UnMap_Mem) (
+ AdapterInfo->Unique_ID,
+ MemAddr,
+ Size,
+ Direction,
+ MappedAddr
+ );
+
+ }
+ }
+
+ return ;
+}
+
+VOID
+DelayIt (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ UINT16 MicroSeconds
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+
+Returns:
+
+--*/
+// TODO: MicroSeconds - add argument and description to function comment
+{
+ if (AdapterInfo->VersionFlag == 0x30) {
+ (*AdapterInfo->Delay_30) (MicroSeconds);
+ } else {
+ (*AdapterInfo->Delay) (AdapterInfo->Unique_ID, MicroSeconds);
+ }
+}
+
+VOID
+BlockIt (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ UINT32 flag
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+
+Returns:
+
+--*/
+// TODO: flag - add argument and description to function comment
+{
+ if (AdapterInfo->VersionFlag == 0x30) {
+ (*AdapterInfo->Block_30) (flag);
+ } else {
+ (*AdapterInfo->Block) (AdapterInfo->Unique_ID, flag);
+ }
+}
+
+UINT8
+Load_Base_Regs (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ //
+ // we will use the linear (flat) memory model and fill our base registers
+ // with 0's so that the entire physical address is our offset
+ //
+ //
+ // we reset the statistics totals here because this is where we are loading stats addr
+ //
+ AdapterInfo->RxTotals = 0;
+ AdapterInfo->TxTotals = 0;
+
+ //
+ // Load the statistics block address.
+ //
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+ OutLong (AdapterInfo, (UINT32) AdapterInfo->stat_phy_addr, AdapterInfo->ioaddr + SCBPointer);
+ OutByte (AdapterInfo, CU_STATSADDR, AdapterInfo->ioaddr + SCBCmd);
+ AdapterInfo->statistics->done_marker = 0;
+
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+ OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer);
+ OutByte (AdapterInfo, RX_ADDR_LOAD, AdapterInfo->ioaddr + SCBCmd);
+
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+ OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer);
+ OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd);
+
+ return 0;
+}
+
+UINT8
+IssueCB (
+ NIC_DATA_INSTANCE *AdapterInfo,
+ TxCB *cmd_ptr
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ cmd_ptr - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ UINT16 status;
+
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+
+ //
+ // read the CU status, if it is idle, write the address of cb_ptr
+ // in the scbpointer and issue a cu_start,
+ // if it is suspended, remove the suspend bit in the previous command
+ // block and issue a resume
+ //
+ // Ensure that the CU Active Status bit is not on from previous CBs.
+ //
+ status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
+
+ //
+ // Skip acknowledging the interrupt if it is not already set
+ //
+
+ //
+ // ack only the cna the integer
+ //
+ if ((status & SCB_STATUS_CNA) != 0) {
+ OutWord (AdapterInfo, SCB_STATUS_CNA, AdapterInfo->ioaddr + SCBStatus);
+
+ }
+
+ if ((status & SCB_STATUS_CU_MASK) == SCB_STATUS_CU_IDLE) {
+ //
+ // give a cu_start
+ //
+ OutLong (AdapterInfo, cmd_ptr->PhysTCBAddress, AdapterInfo->ioaddr + SCBPointer);
+ OutByte (AdapterInfo, CU_START, AdapterInfo->ioaddr + SCBCmd);
+ } else {
+ //
+ // either active or suspended, give a resume
+ //
+
+ cmd_ptr->PrevTCBVirtualLinkPtr->cb_header.command &= ~(CmdSuspend | CmdIntr);
+ OutByte (AdapterInfo, CU_RESUME, AdapterInfo->ioaddr + SCBCmd);
+ }
+
+ return 0;
+}
+
+UINT8
+Configure (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ //
+ // all command blocks are of TxCB format
+ //
+ TxCB *cmd_ptr;
+ UINT8 *data_ptr;
+ INT16 Index;
+ UINT8 my_filter;
+
+ cmd_ptr = GetFreeCB (AdapterInfo);
+ data_ptr = (UINT8 *) (&cmd_ptr->PhysTBDArrayAddres);
+
+ //
+ // start the config data right after the command header
+ //
+ for (Index = 0; Index < sizeof (basic_config_cmd); Index++) {
+ data_ptr[Index] = basic_config_cmd[Index];
+ }
+
+ my_filter = (UINT8) ((AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS) ? 1 : 0);
+ my_filter |= (AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST) ? 0 : 2;
+
+ data_ptr[15] |= my_filter;
+ data_ptr[19] = (UINT8) (AdapterInfo->Duplex ? 0xC0 : 0x80);
+ data_ptr[21] = (UINT8) ((AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) ? 0x0D : 0x05);
+
+ //
+ // check if we have to use the AUI port instead
+ //
+ if ((AdapterInfo->PhyRecord[0] & 0x8000) != 0) {
+ data_ptr[15] |= 0x80;
+ data_ptr[8] = 0;
+ }
+
+ BlockIt (AdapterInfo, TRUE);
+ cmd_ptr->cb_header.command = CmdSuspend | CmdConfigure;
+
+ IssueCB (AdapterInfo, cmd_ptr);
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+
+ BlockIt (AdapterInfo, FALSE);
+
+ CommandWaitForCompletion (cmd_ptr, AdapterInfo);
+
+ //
+ // restore the cb values for tx
+ //
+ cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;
+ cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;
+ //
+ // fields beyond the immediatedata are assumed to be safe
+ // add the CB to the free list again
+ //
+ SetFreeCB (AdapterInfo, cmd_ptr);
+ return 0;
+}
+
+UINT8
+E100bSetupIAAddr (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ //
+ // all command blocks are of TxCB format
+ //
+ TxCB *cmd_ptr;
+ UINT16 *data_ptr;
+ UINT16 *eaddrs;
+
+ eaddrs = (UINT16 *) AdapterInfo->CurrentNodeAddress;
+
+ cmd_ptr = GetFreeCB (AdapterInfo);
+ data_ptr = (UINT16 *) (&cmd_ptr->PhysTBDArrayAddres);
+
+ //
+ // AVOID a bug (?!) here by marking the command already completed.
+ //
+ cmd_ptr->cb_header.command = (CmdSuspend | CmdIASetup);
+ cmd_ptr->cb_header.status = 0;
+ data_ptr[0] = eaddrs[0];
+ data_ptr[1] = eaddrs[1];
+ data_ptr[2] = eaddrs[2];
+
+ BlockIt (AdapterInfo, TRUE);
+ IssueCB (AdapterInfo, cmd_ptr);
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+ BlockIt (AdapterInfo, FALSE);
+
+ CommandWaitForCompletion (cmd_ptr, AdapterInfo);
+
+ //
+ // restore the cb values for tx
+ //
+ cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;
+ cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;
+ //
+ // fields beyond the immediatedata are assumed to be safe
+ // add the CB to the free list again
+ //
+ SetFreeCB (AdapterInfo, cmd_ptr);
+ return 0;
+}
+
+VOID
+StopRU (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ Instructs the NIC to stop receiving packets.
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+Returns:
+
+--*/
+{
+ if (AdapterInfo->Receive_Started) {
+
+ //
+ // Todo: verify that we must wait for previous command completion.
+ //
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+
+ //
+ // Disable interrupts, and stop the chip's Rx process.
+ //
+ OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
+ OutWord (AdapterInfo, INT_MASK | RX_ABORT, AdapterInfo->ioaddr + SCBCmd);
+
+ AdapterInfo->Receive_Started = FALSE;
+ }
+
+ return ;
+}
+
+INT8
+StartRU (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ Instructs the NIC to start receiving packets.
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+Returns:
+ 0 - Successful
+ -1 - Already Started
+--*/
+{
+
+ if (AdapterInfo->Receive_Started) {
+ //
+ // already started
+ //
+ return -1;
+ }
+
+ AdapterInfo->cur_rx_ind = 0;
+ AdapterInfo->Int_Status = 0;
+
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+
+ OutLong (AdapterInfo, (UINT32) AdapterInfo->rx_phy_addr, AdapterInfo->ioaddr + SCBPointer);
+ OutByte (AdapterInfo, RX_START, AdapterInfo->ioaddr + SCBCmd);
+
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+
+ AdapterInfo->Receive_Started = TRUE;
+ return 0;
+}
+
+UINTN
+E100bInit (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ Configures the chip. This routine expects the NIC_DATA_INSTANCE structure to be filled in.
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+
+Returns:
+ 0 - Successful
+ PXE_STATCODE_NOT_ENOUGH_MEMORY - Insufficient length of locked memory
+ other - Failure initializing chip
+--*/
+{
+ PCI_CONFIG_HEADER *CfgHdr;
+ UINTN stat;
+ UINTN rx_size;
+ UINTN tx_size;
+
+ if (AdapterInfo->MemoryLength < MEMORY_NEEDED) {
+ return PXE_STATCODE_NOT_ENOUGH_MEMORY;
+ }
+
+ stat = MapIt (
+ AdapterInfo,
+ AdapterInfo->MemoryPtr,
+ AdapterInfo->MemoryLength,
+ TO_AND_FROM_DEVICE,
+ (UINT64)(UINTN) &AdapterInfo->Mapped_MemoryPtr
+ );
+
+ if (stat != 0) {
+ return stat;
+ }
+
+ CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);
+
+ //
+ // fill in the ioaddr, int... from the config space
+ //
+ AdapterInfo->int_num = CfgHdr->int_line;
+
+ //
+ // we don't need to validate integer number, what if they don't want to assign one?
+ // if (AdapterInfo->int_num == 0 || AdapterInfo->int_num == 0xff)
+ // return PXE_STATCODE_DEVICE_FAILURE;
+ //
+ AdapterInfo->ioaddr = 0;
+ AdapterInfo->VendorID = CfgHdr->VendorID;
+ AdapterInfo->DeviceID = CfgHdr->DeviceID;
+ AdapterInfo->RevID = CfgHdr->RevID;
+ AdapterInfo->SubVendorID = CfgHdr->SubVendorID;
+ AdapterInfo->SubSystemID = CfgHdr->SubSystemID;
+ AdapterInfo->flash_addr = 0;
+
+ //
+ // Read the station address EEPROM before doing the reset.
+ // Perhaps this should even be done before accepting the device,
+ // then we wouldn't have a device name with which to report the error.
+ //
+ if (E100bReadEepromAndStationAddress (AdapterInfo) != 0) {
+ return PXE_STATCODE_DEVICE_FAILURE;
+
+ }
+ //
+ // ## calculate the buffer #s depending on memory given
+ // ## calculate the rx and tx ring pointers
+ //
+
+ AdapterInfo->TxBufCnt = TX_BUFFER_COUNT;
+ AdapterInfo->RxBufCnt = RX_BUFFER_COUNT;
+ rx_size = (AdapterInfo->RxBufCnt * sizeof (RxFD));
+ tx_size = (AdapterInfo->TxBufCnt * sizeof (TxCB));
+ AdapterInfo->rx_ring = (RxFD *) (UINTN) (AdapterInfo->MemoryPtr);
+ AdapterInfo->tx_ring = (TxCB *) (UINTN) (AdapterInfo->MemoryPtr + rx_size);
+ AdapterInfo->statistics = (struct speedo_stats *) (UINTN) (AdapterInfo->MemoryPtr + rx_size + tx_size);
+
+ AdapterInfo->rx_phy_addr = AdapterInfo->Mapped_MemoryPtr;
+ AdapterInfo->tx_phy_addr = AdapterInfo->Mapped_MemoryPtr + rx_size;
+ AdapterInfo->stat_phy_addr = AdapterInfo->tx_phy_addr + tx_size;
+
+ //
+ // auto detect.
+ //
+ AdapterInfo->PhyAddress = 0xFF;
+ AdapterInfo->Rx_Filter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
+ AdapterInfo->Receive_Started = FALSE;
+ AdapterInfo->mcast_list.list_len = 0;
+ return InitializeChip (AdapterInfo);
+}
+
+UINT8
+E100bSetInterruptState (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ Sets the interrupt state for the NIC.
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+Returns:
+ 0 - Successful
+--*/
+{
+ //
+ // don't set receive interrupt if receiver is disabled...
+ //
+ UINT16 cmd_word;
+
+ if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {
+ cmd_word = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd);
+ cmd_word &= ~INT_MASK;
+ OutWord (AdapterInfo, cmd_word, AdapterInfo->ioaddr + SCBCmd);
+ } else {
+ //
+ // disable ints, should not be given for SW Int.
+ //
+ OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
+ }
+
+ if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_SOFTWARE) != 0) {
+ //
+ // reset the bit in our mask, it is only one time!!
+ //
+ AdapterInfo->int_mask &= ~(PXE_OPFLAGS_INTERRUPT_SOFTWARE);
+ cmd_word = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd);
+ cmd_word |= DRVR_INT;
+ OutWord (AdapterInfo, cmd_word, AdapterInfo->ioaddr + SCBCmd);
+ }
+
+ return 0;
+}
+//
+// we are not going to disable broadcast for the WOL's sake!
+//
+UINTN
+E100bSetfilter (
+ NIC_DATA_INSTANCE *AdapterInfo,
+ UINT16 new_filter,
+ UINT64 cpb,
+ UINT32 cpbsize
+ )
+/*++
+
+Routine Description:
+ Instructs the NIC to start receiving packets.
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+ new_filter -
+ cpb -
+ cpbsize -
+
+Returns:
+ 0 - Successful
+ -1 - Already Started
+--*/
+{
+ PXE_CPB_RECEIVE_FILTERS *mc_list = (PXE_CPB_RECEIVE_FILTERS *) (UINTN)cpb;
+ UINT16 cfg_flt;
+ UINT16 old_filter;
+ UINT16 Index;
+ UINT16 Index2;
+ UINT16 mc_count;
+ TxCB *cmd_ptr;
+ struct MC_CB_STRUCT *data_ptr;
+ UINT16 mc_byte_cnt;
+
+ old_filter = AdapterInfo->Rx_Filter;
+
+ //
+ // only these bits need a change in the configuration
+ // actually change in bcast requires configure but we ignore that change
+ //
+ cfg_flt = PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |
+ PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+
+ if ((old_filter & cfg_flt) != (new_filter & cfg_flt)) {
+ XmitWaitForCompletion (AdapterInfo);
+
+ if (AdapterInfo->Receive_Started) {
+ StopRU (AdapterInfo);
+ }
+
+ AdapterInfo->Rx_Filter = (UINT8) (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST);
+ Configure (AdapterInfo);
+ }
+
+ //
+ // check if mcast setting changed
+ //
+ if ( ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=
+ (old_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) ) ||
+ (mc_list != NULL) ) {
+
+
+ if (mc_list != NULL) {
+ mc_count = AdapterInfo->mcast_list.list_len = (UINT16) (cpbsize / PXE_MAC_LENGTH);
+
+ for (Index = 0; (Index < mc_count && Index < MAX_MCAST_ADDRESS_CNT); Index++) {
+ for (Index2 = 0; Index2 < PXE_MAC_LENGTH; Index2++) {
+ AdapterInfo->mcast_list.mc_list[Index][Index2] = mc_list->MCastList[Index][Index2];
+ }
+ }
+ }
+
+ //
+ // are we setting the list or resetting??
+ //
+ if ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
+ //
+ // we are setting a new list!
+ //
+ mc_count = AdapterInfo->mcast_list.list_len;
+ //
+ // count should be the actual # of bytes in the list
+ // so multiply this with 6
+ //
+ mc_byte_cnt = (UINT16) ((mc_count << 2) + (mc_count << 1));
+ AdapterInfo->Rx_Filter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+ } else {
+ //
+ // disabling the list in the NIC.
+ //
+ mc_byte_cnt = mc_count = 0;
+ AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
+ }
+
+ //
+ // before issuing any new command!
+ //
+ XmitWaitForCompletion (AdapterInfo);
+
+ if (AdapterInfo->Receive_Started) {
+ StopRU (AdapterInfo);
+
+ }
+
+ cmd_ptr = GetFreeCB (AdapterInfo);
+ if (cmd_ptr == NULL) {
+ return PXE_STATCODE_QUEUE_FULL;
+ }
+ //
+ // fill the command structure and issue
+ //
+ data_ptr = (struct MC_CB_STRUCT *) (&cmd_ptr->PhysTBDArrayAddres);
+ //
+ // first 2 bytes are the count;
+ //
+ data_ptr->count = mc_byte_cnt;
+ for (Index = 0; Index < mc_count; Index++) {
+ for (Index2 = 0; Index2 < PXE_HWADDR_LEN_ETHER; Index2++) {
+ data_ptr->m_list[Index][Index2] = AdapterInfo->mcast_list.mc_list[Index][Index2];
+ }
+ }
+
+ cmd_ptr->cb_header.command = CmdSuspend | CmdMulticastList;
+ cmd_ptr->cb_header.status = 0;
+
+ BlockIt (AdapterInfo, TRUE);
+ IssueCB (AdapterInfo, cmd_ptr);
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+
+ BlockIt (AdapterInfo, FALSE);
+
+ CommandWaitForCompletion (cmd_ptr, AdapterInfo);
+
+ cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;
+ cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;
+ //
+ // fields beyond the immediatedata are assumed to be safe
+ // add the CB to the free list again
+ //
+ SetFreeCB (AdapterInfo, cmd_ptr);
+ }
+
+ if (new_filter != 0) {
+ //
+ // enable unicast and start the RU
+ //
+ AdapterInfo->Rx_Filter |= (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_UNICAST);
+ StartRU (AdapterInfo);
+ } else {
+ //
+ // may be disabling everything!
+ //
+ if (AdapterInfo->Receive_Started) {
+ StopRU (AdapterInfo);
+ }
+
+ AdapterInfo->Rx_Filter |= (~PXE_OPFLAGS_RECEIVE_FILTER_UNICAST);
+ }
+
+ return 0;
+}
+
+UINTN
+E100bTransmit (
+ NIC_DATA_INSTANCE *AdapterInfo,
+ UINT64 cpb,
+ UINT16 opflags
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ cpb - TODO: add argument description
+ opflags - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ PXE_CPB_TRANSMIT_FRAGMENTS *tx_ptr_f;
+ PXE_CPB_TRANSMIT *tx_ptr_1;
+ TxCB *tcb_ptr;
+ UINT64 Tmp_ptr;
+ UINTN stat;
+ INT32 Index;
+ UINT16 wait_sec;
+
+ tx_ptr_1 = (PXE_CPB_TRANSMIT *) (UINTN) cpb;
+ tx_ptr_f = (PXE_CPB_TRANSMIT_FRAGMENTS *) (UINTN) cpb;
+
+ //
+ // stop reentrancy here
+ //
+ if (AdapterInfo->in_transmit) {
+ return PXE_STATCODE_BUSY;
+
+ }
+
+ AdapterInfo->in_transmit = TRUE;
+
+ //
+ // Prevent interrupts from changing the Tx ring from underneath us.
+ //
+ // Calculate the Tx descriptor entry.
+ //
+ if ((tcb_ptr = GetFreeCB (AdapterInfo)) == NULL) {
+ AdapterInfo->in_transmit = FALSE;
+ return PXE_STATCODE_QUEUE_FULL;
+ }
+
+ AdapterInfo->TxTotals++;
+
+ tcb_ptr->cb_header.command = (CmdSuspend | CmdTx | CmdTxFlex);
+ tcb_ptr->cb_header.status = 0;
+
+ //
+ // no immediate data, set EOF in the ByteCount
+ //
+ tcb_ptr->ByteCount = 0x8000;
+
+ //
+ // The data region is always in one buffer descriptor, Tx FIFO
+ // threshold of 256.
+ // 82557 multiplies the threashold value by 8, so give 256/8
+ //
+ tcb_ptr->Threshold = 32;
+ if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
+
+ if (tx_ptr_f->FragCnt > MAX_XMIT_FRAGMENTS) {
+ SetFreeCB (AdapterInfo, tcb_ptr);
+ AdapterInfo->in_transmit = FALSE;
+ return PXE_STATCODE_INVALID_PARAMETER;
+ }
+
+ tcb_ptr->TBDCount = (UINT8) tx_ptr_f->FragCnt;
+
+ for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) {
+ stat = MapIt (
+ AdapterInfo,
+ tx_ptr_f->FragDesc[Index].FragAddr,
+ tx_ptr_f->FragDesc[Index].FragLen,
+ TO_DEVICE,
+ (UINT64)(UINTN) &Tmp_ptr
+ );
+ if (stat != 0) {
+ SetFreeCB (AdapterInfo, tcb_ptr);
+ AdapterInfo->in_transmit = FALSE;
+ return PXE_STATCODE_INVALID_PARAMETER;
+ }
+
+ tcb_ptr->TBDArray[Index].phys_buf_addr = (UINT32) Tmp_ptr;
+ tcb_ptr->TBDArray[Index].buf_len = tx_ptr_f->FragDesc[Index].FragLen;
+ }
+
+ tcb_ptr->free_data_ptr = tx_ptr_f->FragDesc[0].FragAddr;
+
+ } else {
+ //
+ // non fragmented case
+ //
+ tcb_ptr->TBDCount = 1;
+ stat = MapIt (
+ AdapterInfo,
+ tx_ptr_1->FrameAddr,
+ tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen,
+ TO_DEVICE,
+ (UINT64)(UINTN) &Tmp_ptr
+ );
+ if (stat != 0) {
+ SetFreeCB (AdapterInfo, tcb_ptr);
+ AdapterInfo->in_transmit = FALSE;
+ return PXE_STATCODE_INVALID_PARAMETER;
+ }
+
+ tcb_ptr->TBDArray[0].phys_buf_addr = (UINT32) (Tmp_ptr);
+ tcb_ptr->TBDArray[0].buf_len = tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen;
+ tcb_ptr->free_data_ptr = tx_ptr_1->FrameAddr;
+ }
+
+ //
+ // must wait for previous command completion only if it was a non-transmit
+ //
+ BlockIt (AdapterInfo, TRUE);
+ IssueCB (AdapterInfo, tcb_ptr);
+ BlockIt (AdapterInfo, FALSE);
+
+ //
+ // see if we need to wait for completion here
+ //
+ if ((opflags & PXE_OPFLAGS_TRANSMIT_BLOCK) != 0) {
+ //
+ // don't wait for more than 1 second!!!
+ //
+ wait_sec = 1000;
+ while (tcb_ptr->cb_header.status == 0) {
+ DelayIt (AdapterInfo, 10);
+ wait_sec--;
+ if (wait_sec == 0) {
+ break;
+ }
+ }
+ //
+ // we need to un-map any mapped buffers here
+ //
+ if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
+
+ for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) {
+ Tmp_ptr = tcb_ptr->TBDArray[Index].phys_buf_addr;
+ UnMapIt (
+ AdapterInfo,
+ tx_ptr_f->FragDesc[Index].FragAddr,
+ tx_ptr_f->FragDesc[Index].FragLen,
+ TO_DEVICE,
+ (UINT64) Tmp_ptr
+ );
+ }
+ } else {
+ Tmp_ptr = tcb_ptr->TBDArray[0].phys_buf_addr;
+ UnMapIt (
+ AdapterInfo,
+ tx_ptr_1->FrameAddr,
+ tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen,
+ TO_DEVICE,
+ (UINT64) Tmp_ptr
+ );
+ }
+
+ if (tcb_ptr->cb_header.status == 0) {
+ SetFreeCB (AdapterInfo, tcb_ptr);
+ AdapterInfo->in_transmit = FALSE;
+ return PXE_STATCODE_DEVICE_FAILURE;
+ }
+
+ SetFreeCB (AdapterInfo, tcb_ptr);
+ }
+ //
+ // CB will be set free later in get_status (or when we run out of xmit buffers
+ //
+ AdapterInfo->in_transmit = FALSE;
+
+ return 0;
+}
+
+UINTN
+E100bReceive (
+ NIC_DATA_INSTANCE *AdapterInfo,
+ UINT64 cpb,
+ UINT64 db
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ cpb - TODO: add argument description
+ db - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ PXE_CPB_RECEIVE *rx_cpbptr;
+ PXE_DB_RECEIVE *rx_dbptr;
+ RxFD *rx_ptr;
+ INT32 status;
+ INT32 Index;
+ UINT16 pkt_len;
+ UINT16 ret_code;
+ PXE_FRAME_TYPE pkt_type;
+ UINT16 Tmp_len;
+ EtherHeader *hdr_ptr;
+ ret_code = PXE_STATCODE_NO_DATA;
+ pkt_type = PXE_FRAME_TYPE_NONE;
+ status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
+ AdapterInfo->Int_Status |= status;
+ //
+ // acknoledge the interrupts
+ //
+ OutWord (AdapterInfo, (UINT16) (status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));
+
+ //
+ // include the prev ints as well
+ //
+ status = AdapterInfo->Int_Status;
+ rx_cpbptr = (PXE_CPB_RECEIVE *) (UINTN) cpb;
+ rx_dbptr = (PXE_DB_RECEIVE *) (UINTN) db;
+
+ rx_ptr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];
+
+ //
+ // be in a loop just in case (we may drop a pkt)
+ //
+ while ((status = rx_ptr->cb_header.status) & RX_COMPLETE) {
+
+ AdapterInfo->RxTotals++;
+ //
+ // If we own the next entry, it's a new packet. Send it up.
+ //
+ if (rx_ptr->forwarded) {
+ goto FreeRFD;
+
+ }
+
+ //
+ // discard bad frames
+ //
+
+ //
+ // crc, align, dma overrun, too short, receive error (v22 no coll)
+ //
+ if ((status & 0x0D90) != 0) {
+ goto FreeRFD;
+
+ }
+
+ //
+ // make sure the status is OK
+ //
+ if ((status & 0x02000) == 0) {
+ goto FreeRFD;
+ }
+
+ pkt_len = (UINT16) (rx_ptr->ActualCount & 0x3fff);
+
+ if (pkt_len != 0) {
+
+ Tmp_len = pkt_len;
+ if (pkt_len > rx_cpbptr->BufferLen) {
+ Tmp_len = (UINT16) rx_cpbptr->BufferLen;
+ }
+
+ CopyMem ((INT8 *) (UINTN) rx_cpbptr->BufferAddr, (INT8 *) &rx_ptr->RFDBuffer, Tmp_len);
+
+ hdr_ptr = (EtherHeader *) &rx_ptr->RFDBuffer;
+ //
+ // fill the CDB and break the loop
+ //
+
+ //
+ // includes header
+ //
+ rx_dbptr->FrameLen = pkt_len;
+ rx_dbptr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
+
+ for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
+ if (hdr_ptr->dest_addr[Index] != AdapterInfo->CurrentNodeAddress[Index]) {
+ break;
+ }
+ }
+
+ if (Index >= PXE_HWADDR_LEN_ETHER) {
+ pkt_type = PXE_FRAME_TYPE_UNICAST;
+ } else {
+ for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
+ if (hdr_ptr->dest_addr[Index] != AdapterInfo->BroadcastNodeAddress[Index]) {
+ break;
+ }
+ }
+
+ if (Index >= PXE_HWADDR_LEN_ETHER) {
+ pkt_type = PXE_FRAME_TYPE_BROADCAST;
+ } else {
+ if ((hdr_ptr->dest_addr[0] & 1) == 1) {
+ //
+ // mcast
+ //
+
+ pkt_type = PXE_FRAME_TYPE_MULTICAST;
+ } else {
+ pkt_type = PXE_FRAME_TYPE_PROMISCUOUS;
+ }
+ }
+ }
+
+ rx_dbptr->Type = pkt_type;
+ rx_dbptr->Protocol = hdr_ptr->type;
+
+ for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
+ rx_dbptr->SrcAddr[Index] = hdr_ptr->src_addr[Index];
+ rx_dbptr->DestAddr[Index] = hdr_ptr->dest_addr[Index];
+ }
+
+ rx_ptr->forwarded = TRUE;
+ //
+ // success
+ //
+ ret_code = 0;
+ Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind);
+ AdapterInfo->cur_rx_ind++;
+ if (AdapterInfo->cur_rx_ind == AdapterInfo->RxBufCnt) {
+ AdapterInfo->cur_rx_ind = 0;
+ }
+ break;
+ }
+
+FreeRFD:
+ Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind);
+ AdapterInfo->cur_rx_ind++;
+ if (AdapterInfo->cur_rx_ind == AdapterInfo->RxBufCnt) {
+ AdapterInfo->cur_rx_ind = 0;
+ }
+
+ rx_ptr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];
+ }
+
+ if (pkt_type == PXE_FRAME_TYPE_NONE) {
+ AdapterInfo->Int_Status &= (~SCB_STATUS_FR);
+ }
+
+ status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
+ if ((status & SCB_RUS_NO_RESOURCES) != 0) {
+ //
+ // start the receive unit here!
+ // leave all the filled frames,
+ //
+ SetupReceiveQueues (AdapterInfo);
+ OutLong (AdapterInfo, (UINT32) AdapterInfo->rx_phy_addr, AdapterInfo->ioaddr + SCBPointer);
+ OutWord (AdapterInfo, RX_START, AdapterInfo->ioaddr + SCBCmd);
+ AdapterInfo->cur_rx_ind = 0;
+ }
+
+ return ret_code;
+}
+
+INT16
+E100bReadEepromAndStationAddress (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ INT32 Index;
+ INT32 Index2;
+ UINT16 sum;
+ UINT16 eeprom_len;
+ UINT8 addr_len;
+ UINT16 *eedata;
+
+ eedata = (UINT16 *) (&AdapterInfo->NVData[0]);
+
+ sum = 0;
+ addr_len = E100bGetEepromAddrLen (AdapterInfo);
+
+ //
+ // in words
+ //
+ AdapterInfo->NVData_Len = eeprom_len = (UINT16) (1 << addr_len);
+ for (Index2 = 0, Index = 0; Index < eeprom_len; Index++) {
+ UINT16 value;
+ value = E100bReadEeprom (AdapterInfo, Index, addr_len);
+ eedata[Index] = value;
+ sum = (UINT16) (sum + value);
+ if (Index < 3) {
+ AdapterInfo->PermNodeAddress[Index2++] = (UINT8) value;
+ AdapterInfo->PermNodeAddress[Index2++] = (UINT8) (value >> 8);
+ }
+ }
+
+ if (sum != 0xBABA) {
+ return -1;
+ }
+
+ for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
+ AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];
+ }
+
+ for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
+ AdapterInfo->BroadcastNodeAddress[Index] = 0xff;
+ }
+
+ for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
+ AdapterInfo->CurrentNodeAddress[Index] = 0;
+ AdapterInfo->PermNodeAddress[Index] = 0;
+ AdapterInfo->BroadcastNodeAddress[Index] = 0;
+ }
+
+ return 0;
+}
+
+//
+// CBList is a circular linked list
+// 1) When all are free, Tail->next == Head and FreeCount == # allocated
+// 2) When none are free, Tail == Head and FreeCount == 0
+// 3) when one is free, Tail == Head and Freecount == 1
+// 4) First non-Free frame is always at Tail->next
+//
+UINT8
+SetupCBlink (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ TxCB *head_ptr;
+ TxCB *tail_ptr;
+ TxCB *cur_ptr;
+ INT32 Index;
+ UINTN array_off;
+
+ cur_ptr = &(AdapterInfo->tx_ring[0]);
+ array_off = (UINTN) (&cur_ptr->TBDArray) - (UINTN) cur_ptr;
+ for (Index = 0; Index < AdapterInfo->TxBufCnt; Index++) {
+ cur_ptr[Index].cb_header.status = 0;
+ cur_ptr[Index].cb_header.command = 0;
+
+ cur_ptr[Index].PhysTCBAddress =
+ (UINT32) AdapterInfo->tx_phy_addr + (Index * sizeof (TxCB));
+
+ cur_ptr[Index].PhysArrayAddr = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off);
+ cur_ptr[Index].PhysTBDArrayAddres = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off);
+
+ cur_ptr->free_data_ptr = (UINT64) 0;
+
+ if (Index < AdapterInfo->TxBufCnt - 1) {
+ cur_ptr[Index].cb_header.link = cur_ptr[Index].PhysTCBAddress + sizeof (TxCB);
+ cur_ptr[Index].NextTCBVirtualLinkPtr = &cur_ptr[Index + 1];
+ cur_ptr[Index + 1].PrevTCBVirtualLinkPtr = &cur_ptr[Index];
+ }
+ }
+
+ head_ptr = &cur_ptr[0];
+ tail_ptr = &cur_ptr[AdapterInfo->TxBufCnt - 1];
+ tail_ptr->cb_header.link = head_ptr->PhysTCBAddress;
+ tail_ptr->NextTCBVirtualLinkPtr = head_ptr;
+ head_ptr->PrevTCBVirtualLinkPtr = tail_ptr;
+
+ AdapterInfo->FreeCBCount = AdapterInfo->TxBufCnt;
+ AdapterInfo->FreeTxHeadPtr = head_ptr;
+ //
+ // set tail of the free list, next to this would be either in use
+ // or the head itself
+ //
+ AdapterInfo->FreeTxTailPtr = tail_ptr;
+
+ AdapterInfo->xmit_done_head = AdapterInfo->xmit_done_tail = 0;
+
+ return 0;
+}
+
+TxCB *
+GetFreeCB (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ TxCB *free_cb_ptr;
+
+ //
+ // claim any hanging free CBs
+ //
+ if (AdapterInfo->FreeCBCount <= 1) {
+ CheckCBList (AdapterInfo);
+ }
+
+ //
+ // don't use up the last CB problem if the previous CB that the CU used
+ // becomes the last CB we submit because of the SUSPEND bit we set.
+ // the CU thinks it was never cleared.
+ //
+
+ if (AdapterInfo->FreeCBCount <= 1) {
+ return NULL;
+ }
+
+ BlockIt (AdapterInfo, TRUE);
+ free_cb_ptr = AdapterInfo->FreeTxHeadPtr;
+ AdapterInfo->FreeTxHeadPtr = free_cb_ptr->NextTCBVirtualLinkPtr;
+ --AdapterInfo->FreeCBCount;
+ BlockIt (AdapterInfo, FALSE);
+ return free_cb_ptr;
+}
+
+VOID
+SetFreeCB (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN TxCB *cb_ptr
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ cb_ptr - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ //
+ // here we assume cb are returned in the order they are taken out
+ // and we link the newly freed cb at the tail of free cb list
+ //
+ cb_ptr->cb_header.status = 0;
+ cb_ptr->free_data_ptr = (UINT64) 0;
+
+ AdapterInfo->FreeTxTailPtr = cb_ptr;
+ ++AdapterInfo->FreeCBCount;
+ return ;
+}
+
+UINT16
+next (
+ IN UINT16 ind
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ ind - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ UINT16 Tmp;
+
+ Tmp = (UINT16) (ind + 1);
+ if (Tmp >= (TX_BUFFER_COUNT << 1)) {
+ Tmp = 0;
+ }
+
+ return Tmp;
+}
+
+UINT16
+CheckCBList (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ TxCB *Tmp_ptr;
+ UINT16 cnt;
+
+ cnt = 0;
+ while (1) {
+ Tmp_ptr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr;
+ if ((Tmp_ptr->cb_header.status & CMD_STATUS_MASK) != 0) {
+ //
+ // check if Q is full
+ //
+ if (next (AdapterInfo->xmit_done_tail) != AdapterInfo->xmit_done_head) {
+ AdapterInfo->xmit_done[AdapterInfo->xmit_done_tail] = Tmp_ptr->free_data_ptr;
+
+ UnMapIt (
+ AdapterInfo,
+ Tmp_ptr->free_data_ptr,
+ Tmp_ptr->TBDArray[0].buf_len,
+ TO_DEVICE,
+ (UINT64) Tmp_ptr->TBDArray[0].phys_buf_addr
+ );
+
+ AdapterInfo->xmit_done_tail = next (AdapterInfo->xmit_done_tail);
+ }
+
+ SetFreeCB (AdapterInfo, Tmp_ptr);
+ } else {
+ break;
+ }
+ }
+
+ return cnt;
+}
+//
+// Description : Initialize the RFD list list by linking each element together
+// in a circular list. The simplified memory model is used.
+// All data is in the RFD. The RFDs are linked together and the
+// last one points back to the first one. When the current RFD
+// is processed (frame received), its EL bit is set and the EL
+// bit in the previous RXFD is cleared.
+// Allocation done during INIT, this is making linked list.
+//
+UINT8
+SetupReceiveQueues (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ RxFD *rx_ptr;
+ RxFD *head_ptr;
+ RxFD *tail_ptr;
+ UINT16 Index;
+
+ AdapterInfo->cur_rx_ind = 0;
+ rx_ptr = (&AdapterInfo->rx_ring[0]);
+
+ for (Index = 0; Index < AdapterInfo->RxBufCnt; Index++) {
+ rx_ptr[Index].cb_header.status = 0;
+ rx_ptr[Index].cb_header.command = 0;
+ rx_ptr[Index].RFDSize = RX_BUFFER_SIZE;
+ rx_ptr[Index].ActualCount = 0;
+ //
+ // RBDs not used, simple memory model
+ //
+ rx_ptr[Index].rx_buf_addr = (UINT32) (-1);
+
+ //
+ // RBDs not used, simple memory model
+ //
+ rx_ptr[Index].forwarded = FALSE;
+
+ //
+ // don't use Tmp_ptr if it is beyond the last one
+ //
+ if (Index < AdapterInfo->RxBufCnt - 1) {
+ rx_ptr[Index].cb_header.link = (UINT32) AdapterInfo->rx_phy_addr + ((Index + 1) * sizeof (RxFD));
+ }
+ }
+
+ head_ptr = (&AdapterInfo->rx_ring[0]);
+ tail_ptr = (&AdapterInfo->rx_ring[AdapterInfo->RxBufCnt - 1]);
+ tail_ptr->cb_header.link = (UINT32) AdapterInfo->rx_phy_addr;
+
+ //
+ // set the EL bit
+ //
+ tail_ptr->cb_header.command = 0xC000;
+ AdapterInfo->RFDTailPtr = tail_ptr;
+ return 0;
+}
+
+VOID
+Recycle_RFD (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT16 rx_index
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ rx_index - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ RxFD *rx_ptr;
+ RxFD *tail_ptr;
+ //
+ // change the EL bit and change the AdapterInfo->RxTailPtr
+ // rx_ptr is assumed to be the head of the Q
+ // AdapterInfo->rx_forwarded[rx_index] = FALSE;
+ //
+ rx_ptr = &AdapterInfo->rx_ring[rx_index];
+ tail_ptr = AdapterInfo->RFDTailPtr;
+ //
+ // set el_bit and suspend bit
+ //
+ rx_ptr->cb_header.command = 0xc000;
+ rx_ptr->cb_header.status = 0;
+ rx_ptr->ActualCount = 0;
+ rx_ptr->forwarded = FALSE;
+ AdapterInfo->RFDTailPtr = rx_ptr;
+ //
+ // resetting the el_bit.
+ //
+ tail_ptr->cb_header.command = 0;
+ //
+ // check the receive unit, fix if there is any problem
+ //
+ return ;
+}
+//
+// Serial EEPROM section.
+//
+// EEPROM_Ctrl bits.
+//
+#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
+#define EE_CS 0x02 /* EEPROM chip select. */
+#define EE_DI 0x04 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x01
+#define EE_WRITE_1 0x05
+#define EE_DO 0x08 /* EEPROM chip data out. */
+#define EE_ENB (0x4800 | EE_CS)
+
+//
+// Delay between EEPROM clock transitions.
+// This will actually work with no delay on 33Mhz PCI.
+//
+#define eeprom_delay(nanosec) DelayIt (AdapterInfo, nanosec);
+
+//
+// The EEPROM commands include the alway-set leading bit.
+//
+#define EE_WRITE_CMD 5 // 101b
+#define EE_READ_CMD 6 // 110b
+#define EE_ERASE_CMD (7 << 6)
+
+VOID
+shift_bits_out (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT16 val,
+ IN UINT8 num_bits
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ val - TODO: add argument description
+ num_bits - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ INT32 Index;
+ UINT8 Tmp;
+ UINT32 EEAddr;
+
+ EEAddr = AdapterInfo->ioaddr + SCBeeprom;
+
+ for (Index = num_bits; Index >= 0; Index--) {
+ INT16 dataval;
+
+ //
+ // will be 0 or 4
+ //
+ dataval = (INT16) ((val & (1 << Index)) ? EE_DI : 0);
+
+ //
+ // mask off the data_in bit
+ //
+ Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) &~EE_DI);
+ Tmp |= dataval;
+ OutByte (AdapterInfo, Tmp, EEAddr);
+ eeprom_delay (100);
+ //
+ // raise the eeprom clock
+ //
+ OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (150);
+ //
+ // lower the eeprom clock
+ //
+ OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (150);
+ }
+}
+
+UINT16
+shift_bits_in (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ UINT8 Tmp;
+ INT32 Index;
+ UINT16 retval;
+ UINT32 EEAddr;
+
+ EEAddr = AdapterInfo->ioaddr + SCBeeprom;
+
+ retval = 0;
+ for (Index = 15; Index >= 0; Index--) {
+ //
+ // raise the clock
+ //
+
+ //
+ // mask off the data_in bit
+ //
+ Tmp = InByte (AdapterInfo, EEAddr);
+ OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (100);
+ Tmp = InByte (AdapterInfo, EEAddr);
+ retval = (UINT16) ((retval << 1) | ((Tmp & EE_DO) ? 1 : 0));
+ //
+ // lower the clock
+ //
+ OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (100);
+ }
+
+ return retval;
+}
+
+BOOLEAN
+E100bSetEepromLockOut (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ This routine sets the EEPROM lockout bit to gain exclusive access to the
+ eeprom. the access bit is the most significant bit in the General Control
+ Register 2 in the SCB space.
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ TRUE - if it got the access
+ FALSE - if it fails to get the exclusive access
+
+--*/
+{
+ UINTN wait;
+ UINT8 tmp;
+
+ if ((AdapterInfo->DeviceID == D102_DEVICE_ID) ||
+ (AdapterInfo->RevID >= D102_REVID)) {
+
+ wait = 500;
+
+ while (wait--) {
+
+ tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);
+ tmp |= GCR2_EEPROM_ACCESS_SEMAPHORE;
+ OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2);
+
+ DelayIt (AdapterInfo, 50);
+ tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);
+
+ if (tmp & GCR2_EEPROM_ACCESS_SEMAPHORE) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+VOID
+E100bReSetEepromLockOut (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ This routine Resets the EEPROM lockout bit to giveup access to the
+ eeprom. the access bit is the most significant bit in the General Control
+ Register 2 in the SCB space.
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ UINT8 tmp;
+
+ if ((AdapterInfo->DeviceID == D102_DEVICE_ID) ||
+ (AdapterInfo->RevID >= D102_REVID)) {
+
+ tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);
+ tmp &= ~(GCR2_EEPROM_ACCESS_SEMAPHORE);
+ OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2);
+
+ DelayIt (AdapterInfo, 50);
+ }
+}
+
+UINT16
+E100bReadEeprom (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN INT32 Location,
+ IN UINT8 AddrLen
+ )
+/*++
+
+Routine Description:
+ Using the NIC data structure information, read the EEPROM to get a Word of data for the MAC address.
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+ Location - Word offset into the MAC address to read.
+ AddrLen - Number of bits of address length.
+
+Returns:
+ RetVal - The word read from the EEPROM.
+
+--*/
+{
+ UINT16 RetVal;
+ UINT8 Tmp;
+
+ UINT32 EEAddr;
+ UINT16 ReadCmd;
+
+ EEAddr = AdapterInfo->ioaddr + SCBeeprom;
+ ReadCmd = (UINT16) (Location | (EE_READ_CMD << AddrLen));
+
+ RetVal = 0;
+
+ //
+ // get exclusive access to the eeprom first!
+ //
+ E100bSetEepromLockOut (AdapterInfo);
+
+ //
+ // eeprom control reg bits: x,x,x,x,DO,DI,CS,SK
+ // to write the opcode+data value out one bit at a time in DI starting at msb
+ // and then out a 1 to sk, wait, out 0 to SK and wait
+ // repeat this for all the bits to be written
+ //
+
+ //
+ // 11110010b
+ //
+ Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2);
+ OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr);
+
+ //
+ // 3 for the read opcode 110b
+ //
+ shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + AddrLen));
+
+ //
+ // read the eeprom word one bit at a time
+ //
+ RetVal = shift_bits_in (AdapterInfo);
+
+ //
+ // Terminate the EEPROM access and leave eeprom in a clean state.
+ //
+ Tmp = InByte (AdapterInfo, EEAddr);
+ Tmp &= ~(EE_CS | EE_DI);
+ OutByte (AdapterInfo, Tmp, EEAddr);
+
+ //
+ // raise the clock and lower the eeprom shift clock
+ //
+ OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (100);
+
+ OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (100);
+
+ //
+ // giveup access to the eeprom
+ //
+ E100bReSetEepromLockOut (AdapterInfo);
+
+ return RetVal;
+}
+
+UINT8
+E100bGetEepromAddrLen (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ Using the NIC data structure information, read the EEPROM to determine how many bits of address length
+ this EEPROM is in Words.
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ RetVal - The word read from the EEPROM.
+
+--*/
+{
+ UINT8 Tmp;
+ UINT8 AddrLen;
+ UINT32 EEAddr;
+ //
+ // assume 64word eeprom (so,6 bits of address_length)
+ //
+ UINT16 ReadCmd;
+
+ EEAddr = AdapterInfo->ioaddr + SCBeeprom;
+ ReadCmd = (EE_READ_CMD << 6);
+
+ //
+ // get exclusive access to the eeprom first!
+ //
+ E100bSetEepromLockOut (AdapterInfo);
+
+ //
+ // address we are trying to read is 0
+ // eeprom control reg bits: x,x,x,x,DO,,DI,,CS,SK
+ // to write the opcode+data value out one bit at a time in DI starting at msb
+ // and then out a 1 to sk, wait, out 0 to SK and wait
+ // repeat this for all the bits to be written
+ //
+ Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2);
+
+ //
+ // enable eeprom access
+ //
+ OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr);
+
+ //
+ // 3 for opcode, 6 for the default address len
+ //
+ shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + 6));
+
+ //
+ // (in case of a 64 word eeprom).
+ // read the "dummy zero" from EE_DO to say that the address we wrote
+ // (six 0s) is accepted, write more zeros (until 8) to get a "dummy zero"
+ //
+
+ //
+ // assume the smallest
+ //
+ AddrLen = 6;
+ Tmp = InByte (AdapterInfo, EEAddr);
+ while ((AddrLen < 8) && ((Tmp & EE_DO) != 0)) {
+ OutByte (AdapterInfo, (UINT8) (Tmp &~EE_DI), EEAddr);
+ eeprom_delay (100);
+
+ //
+ // raise the eeprom clock
+ //
+ OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (150);
+
+ //
+ // lower the eeprom clock
+ //
+ OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (150);
+ Tmp = InByte (AdapterInfo, EEAddr);
+ AddrLen++;
+ }
+
+ //
+ // read the eeprom word, even though we don't need this
+ //
+ shift_bits_in (AdapterInfo);
+
+ //
+ // Terminate the EEPROM access.
+ //
+ Tmp = InByte (AdapterInfo, EEAddr);
+ Tmp &= ~(EE_CS | EE_DI);
+ OutByte (AdapterInfo, Tmp, EEAddr);
+
+ //
+ // raise the clock and lower the eeprom shift clock
+ //
+ OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (100);
+
+ OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
+ eeprom_delay (100);
+
+ //
+ // giveup access to the eeprom!
+ //
+ E100bReSetEepromLockOut (AdapterInfo);
+
+ return AddrLen;
+}
+
+UINTN
+E100bStatistics (
+ NIC_DATA_INSTANCE *AdapterInfo,
+ UINT64 DBaddr,
+ UINT16 DBsize
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ DBaddr - TODO: add argument description
+ DBsize - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ PXE_DB_STATISTICS db;
+ //
+ // wait upto one second (each wait is 100 micro s)
+ //
+ UINT32 Wait;
+ Wait = 10000;
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+
+ //
+ // Clear statistics done marker.
+ //
+ AdapterInfo->statistics->done_marker = 0;
+
+ //
+ // Issue statistics dump (or dump w/ reset) command.
+ //
+ OutByte (
+ AdapterInfo,
+ (UINT8) (DBsize ? CU_SHOWSTATS : CU_DUMPSTATS),
+ (UINT32) (AdapterInfo->ioaddr + SCBCmd)
+ );
+
+ //
+ // Wait for command to complete.
+ //
+ // zero the db here just to chew up a little more time.
+ //
+
+ ZeroMem ((VOID *) &db, sizeof db);
+
+ while (Wait != 0) {
+ //
+ // Wait a bit before checking.
+ //
+
+ DelayIt (AdapterInfo, 100);
+
+ //
+ // Look for done marker at end of statistics.
+ //
+
+ switch (AdapterInfo->statistics->done_marker) {
+ case 0xA005:
+ case 0xA007:
+ break;
+
+ default:
+ Wait--;
+ continue;
+ }
+
+ //
+ // if we did not "continue" from the above switch, we are done,
+ //
+ break;
+ }
+
+ //
+ // If this is a reset, we are out of here!
+ //
+ if (DBsize == 0) {
+ return PXE_STATCODE_SUCCESS;
+ }
+
+ //
+ // Convert NIC statistics counter format to EFI/UNDI
+ // specification statistics counter format.
+ //
+
+ //
+ // 54 3210 fedc ba98 7654 3210
+ // db.Supported = 01 0000 0100 1101 0001 0111;
+ //
+ db.Supported = 0x104D17;
+
+ //
+ // Statistics from the NIC
+ //
+
+ db.Data[0x01] = AdapterInfo->statistics->rx_good_frames;
+
+ db.Data[0x02] = AdapterInfo->statistics->rx_runt_errs;
+
+ db.Data[0x08] = AdapterInfo->statistics->rx_crc_errs +
+ AdapterInfo->statistics->rx_align_errs;
+
+ db.Data[0x04] = db.Data[0x02] +
+ db.Data[0x08] +
+ AdapterInfo->statistics->rx_resource_errs +
+ AdapterInfo->statistics->rx_overrun_errs;
+
+ db.Data[0x00] = db.Data[0x01] + db.Data[0x04];
+
+ db.Data[0x0B] = AdapterInfo->statistics->tx_good_frames;
+
+ db.Data[0x0E] = AdapterInfo->statistics->tx_coll16_errs +
+ AdapterInfo->statistics->tx_late_colls +
+ AdapterInfo->statistics->tx_underruns +
+ AdapterInfo->statistics->tx_one_colls +
+ AdapterInfo->statistics->tx_multi_colls;
+
+ db.Data[0x14] = AdapterInfo->statistics->tx_total_colls;
+
+ db.Data[0x0A] = db.Data[0x0B] +
+ db.Data[0x0E] +
+ AdapterInfo->statistics->tx_lost_carrier;
+
+ if (DBsize > sizeof db) {
+ DBsize = sizeof db;
+ }
+
+ CopyMem ((VOID *) (UINTN) DBaddr, (VOID *) &db, (UINTN) DBsize);
+
+ return PXE_STATCODE_SUCCESS;
+}
+
+UINTN
+E100bReset (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN INT32 OpFlags
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+ OpFlags - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+
+ UINT16 save_filter;
+ //
+ // disable the interrupts
+ //
+ OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
+
+ //
+ // wait for the tx queue to complete
+ //
+ CheckCBList (AdapterInfo);
+
+ XmitWaitForCompletion (AdapterInfo);
+
+ if (AdapterInfo->Receive_Started) {
+ StopRU (AdapterInfo);
+ }
+
+ InitializeChip (AdapterInfo);
+
+ //
+ // check the opflags and restart receive filters
+ //
+ if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
+
+ save_filter = AdapterInfo->Rx_Filter;
+ //
+ // if we give the filter same as Rx_Filter,
+ // this routine will not set mcast list (it thinks there is no change)
+ // to force it, we will reset that flag in the Rx_Filter
+ //
+ AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
+ E100bSetfilter (AdapterInfo, save_filter, (UINT64) 0, (UINT32) 0);
+ }
+
+ if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
+ //
+ // disable the interrupts
+ //
+ AdapterInfo->int_mask = 0;
+ }
+ //
+ // else leave the interrupt in the pre-set state!!!
+ //
+ E100bSetInterruptState (AdapterInfo);
+
+ return 0;
+}
+
+UINTN
+E100bShutdown (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ //
+ // disable the interrupts
+ //
+ OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
+
+ //
+ // stop the receive unit
+ //
+ if (AdapterInfo->Receive_Started) {
+ StopRU (AdapterInfo);
+ }
+
+ //
+ // wait for the tx queue to complete
+ //
+ CheckCBList (AdapterInfo);
+ if (AdapterInfo->FreeCBCount != AdapterInfo->TxBufCnt) {
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+ }
+
+ //
+ // we do not want to reset the phy, it takes a long time to renegotiate the
+ // link after that (3-4 seconds)
+ //
+ InitializeChip (AdapterInfo);
+ SelectiveReset (AdapterInfo);
+ return 0;
+}
+
+VOID
+MdiWrite (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT8 RegAddress,
+ IN UINT8 PhyAddress,
+ IN UINT16 DataValue
+ )
+/*++
+
+Routine Description:
+ This routine will write a value to the specified MII register
+ of an external MDI compliant device (e.g. PHY 100). The command will
+ execute in polled mode.
+
+Arguments:
+ AdapterInfo - pointer to the structure that contains the NIC's context.
+ RegAddress - The MII register that we are writing to
+ PhyAddress - The MDI address of the Phy component.
+ DataValue - The value that we are writing to the MII register.
+
+Returns:
+ nothing
+--*/
+{
+ UINT32 WriteCommand;
+
+ WriteCommand = ((UINT32) DataValue) |
+ ((UINT32)(RegAddress << 16)) |
+ ((UINT32)(PhyAddress << 21)) |
+ ((UINT32)(MDI_WRITE << 26));
+
+ //
+ // Issue the write command to the MDI control register.
+ //
+ OutLong (AdapterInfo, WriteCommand, AdapterInfo->ioaddr + SCBCtrlMDI);
+
+ //
+ // wait 20usec before checking status
+ //
+ DelayIt (AdapterInfo, 20);
+
+ //
+ // poll for the mdi write to complete
+ while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) &
+ MDI_PHY_READY) == 0){
+ DelayIt (AdapterInfo, 20);
+ }
+}
+
+VOID
+MdiRead (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT8 RegAddress,
+ IN UINT8 PhyAddress,
+ IN OUT UINT16 *DataValue
+ )
+/*++
+
+Routine Description:
+ This routine will read a value from the specified MII register
+ of an external MDI compliant device (e.g. PHY 100), and return
+ it to the calling routine. The command will execute in polled mode.
+
+Arguments:
+ AdapterInfo - pointer to the structure that contains the NIC's context.
+ RegAddress - The MII register that we are reading from
+ PhyAddress - The MDI address of the Phy component.
+ DataValue - pointer to the value that we read from the MII register.
+
+Returns:
+
+--*/
+{
+ UINT32 ReadCommand;
+
+ ReadCommand = ((UINT32) (RegAddress << 16)) |
+ ((UINT32) (PhyAddress << 21)) |
+ ((UINT32) (MDI_READ << 26));
+
+ //
+ // Issue the read command to the MDI control register.
+ //
+ OutLong (AdapterInfo, ReadCommand, AdapterInfo->ioaddr + SCBCtrlMDI);
+
+ //
+ // wait 20usec before checking status
+ //
+ DelayIt (AdapterInfo, 20);
+
+ //
+ // poll for the mdi read to complete
+ //
+ while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) &
+ MDI_PHY_READY) == 0) {
+ DelayIt (AdapterInfo, 20);
+
+ }
+
+ *DataValue = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI);
+}
+
+VOID
+PhyReset (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ This routine will reset the PHY that the adapter is currently
+ configured to use.
+
+Arguments:
+ AdapterInfo - pointer to the structure that contains the NIC's context.
+
+Returns:
+
+--*/
+{
+ UINT16 MdiControlReg;
+
+ MdiControlReg = (MDI_CR_AUTO_SELECT |
+ MDI_CR_RESTART_AUTO_NEG |
+ MDI_CR_RESET);
+
+ //
+ // Write the MDI control register with our new Phy configuration
+ //
+ MdiWrite (
+ AdapterInfo,
+ MDI_CONTROL_REG,
+ AdapterInfo->PhyAddress,
+ MdiControlReg
+ );
+
+ return ;
+}
+
+BOOLEAN
+PhyDetect (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ This routine will detect what phy we are using, set the line
+ speed, FDX or HDX, and configure the phy if necessary.
+
+ The following combinations are supported:
+ - TX or T4 PHY alone at PHY address 1
+ - T4 or TX PHY at address 1 and MII PHY at address 0
+ - 82503 alone (10Base-T mode, no full duplex support)
+ - 82503 and MII PHY (TX or T4) at address 0
+
+ The sequence / priority of detection is as follows:
+ - PHY 1 with cable termination
+ - PHY 0 with cable termination
+ - PHY 1 (if found) without cable termination
+ - 503 interface
+
+ Additionally auto-negotiation capable (NWAY) and parallel
+ detection PHYs are supported. The flow-chart is described in
+ the 82557 software writer's manual.
+
+ NOTE: 1. All PHY MDI registers are read in polled mode.
+ 2. The routines assume that the 82557 has been RESET and we have
+ obtained the virtual memory address of the CSR.
+ 3. PhyDetect will not RESET the PHY.
+ 4. If FORCEFDX is set, SPEED should also be set. The driver will
+ check the values for inconsistency with the detected PHY
+ technology.
+ 5. PHY 1 (the PHY on the adapter) may have an address in the range
+ 1 through 31 inclusive. The driver will accept addresses in
+ this range.
+ 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface
+ is detected.
+
+Arguments:
+ AdapterInfo - pointer to the structure that contains the NIC's context.
+
+Returns:
+ TRUE - If a Phy was detected, and configured correctly.
+ FALSE - If a valid phy could not be detected and configured.
+
+--*/
+{
+ UINT16 *eedata;
+ UINT16 MdiControlReg;
+ UINT16 MdiStatusReg;
+ BOOLEAN FoundPhy1;
+ UINT8 ReNegotiateTime;
+
+ eedata = (UINT16 *) (&AdapterInfo->NVData[0]);
+
+ FoundPhy1 = FALSE;
+ ReNegotiateTime = 35;
+ //
+ // EEPROM word [6] contains the Primary PHY record in which the least 3 bits
+ // indicate the PHY address
+ // and word [7] contains the secondary PHY record
+ //
+ AdapterInfo->PhyRecord[0] = eedata[6];
+ AdapterInfo->PhyRecord[1] = eedata[7];
+ AdapterInfo->PhyAddress = (UINT8) (AdapterInfo->PhyRecord[0] & 7);
+
+ //
+ // Check for a phy address over-ride of 32 which indicates force use of 82503
+ // not detecting the link in this case
+ //
+ if (AdapterInfo->PhyAddress == 32) {
+ //
+ // 503 interface over-ride
+ // Record the current speed and duplex. We will be in half duplex
+ // mode unless the user used the force full duplex over-ride.
+ //
+ AdapterInfo->LinkSpeed = 10;
+ return (TRUE);
+ }
+
+ //
+ // If the Phy Address is between 1-31 then we must first look for phy 1,
+ // at that address.
+ //
+ if ((AdapterInfo->PhyAddress > 0) && (AdapterInfo->PhyAddress < 32)) {
+
+ //
+ // Read the MDI control and status registers at phy 1
+ // and check if we found a valid phy
+ //
+ MdiRead (
+ AdapterInfo,
+ MDI_CONTROL_REG,
+ AdapterInfo->PhyAddress,
+ &MdiControlReg
+ );
+
+ MdiRead (
+ AdapterInfo,
+ MDI_STATUS_REG,
+ AdapterInfo->PhyAddress,
+ &MdiStatusReg
+ );
+
+ if (!((MdiControlReg == 0xffff) ||
+ ((MdiStatusReg == 0) && (MdiControlReg == 0)))) {
+
+ //
+ // we have a valid phy1
+ // Read the status register again because of sticky bits
+ //
+ FoundPhy1 = TRUE;
+ MdiRead (
+ AdapterInfo,
+ MDI_STATUS_REG,
+ AdapterInfo->PhyAddress,
+ &MdiStatusReg
+ );
+
+ //
+ // If there is a valid link then use this Phy.
+ //
+ if (MdiStatusReg & MDI_SR_LINK_STATUS) {
+ return (SetupPhy(AdapterInfo));
+ }
+ }
+ }
+
+ //
+ // Next try to detect a PHY at address 0x00 because there was no Phy 1,
+ // or Phy 1 didn't have link, or we had a phy 0 over-ride
+ //
+
+ //
+ // Read the MDI control and status registers at phy 0
+ //
+ MdiRead (AdapterInfo, MDI_CONTROL_REG, 0, &MdiControlReg);
+ MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
+
+ //
+ // check if we found a valid phy 0
+ //
+ if (((MdiControlReg == 0xffff) ||
+ ((MdiStatusReg == 0) && (MdiControlReg == 0)))) {
+
+ //
+ // we don't have a valid phy at address 0
+ // if phy address was forced to 0, then error out because we
+ // didn't find a phy at that address
+ //
+ if (AdapterInfo->PhyAddress == 0x0000) {
+ return (FALSE);
+ } else {
+ //
+ // at this point phy1 does not have link and there is no phy 0 at all
+ // if we are forced to detect the cable, error out here!
+ //
+ if (AdapterInfo->CableDetect != 0) {
+ return FALSE;
+
+ }
+
+ if (FoundPhy1) {
+ //
+ // no phy 0, but there is a phy 1 (no link I guess), so use phy 1
+ //
+ return SetupPhy (AdapterInfo);
+ } else {
+ //
+ // didn't find phy 0 or phy 1, so assume a 503 interface
+ //
+ AdapterInfo->PhyAddress = 32;
+
+ //
+ // Record the current speed and duplex. We'll be in half duplex
+ // mode unless the user used the force full duplex over-ride.
+ //
+ AdapterInfo->LinkSpeed = 10;
+ return (TRUE);
+ }
+ }
+ } else {
+ //
+ // We have a valid phy at address 0. If phy 0 has a link then we use
+ // phy 0. If Phy 0 doesn't have a link then we use Phy 1 (no link)
+ // if phy 1 is present, or phy 0 if phy 1 is not present
+ // If phy 1 was present, then we must isolate phy 1 before we enable
+ // phy 0 to see if Phy 0 has a link.
+ //
+ if (FoundPhy1) {
+ //
+ // isolate phy 1
+ //
+ MdiWrite (
+ AdapterInfo,
+ MDI_CONTROL_REG,
+ AdapterInfo->PhyAddress,
+ MDI_CR_ISOLATE
+ );
+
+ //
+ // wait 100 microseconds for the phy to isolate.
+ //
+ DelayIt (AdapterInfo, 100);
+ }
+
+ //
+ // Since this Phy is at address 0, we must enable it. So clear
+ // the isolate bit, and set the auto-speed select bit
+ //
+ MdiWrite (
+ AdapterInfo,
+ MDI_CONTROL_REG,
+ 0,
+ MDI_CR_AUTO_SELECT
+ );
+
+ //
+ // wait 100 microseconds for the phy to be enabled.
+ //
+ DelayIt (AdapterInfo, 100);
+
+ //
+ // restart the auto-negotion process
+ //
+ MdiWrite (
+ AdapterInfo,
+ MDI_CONTROL_REG,
+ 0,
+ MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT
+ );
+
+ //
+ // wait no more than 3.5 seconds for auto-negotiation to complete
+ //
+ while (ReNegotiateTime) {
+ //
+ // Read the status register twice because of sticky bits
+ //
+ MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
+ MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
+
+ if (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE) {
+ break;
+ }
+
+ DelayIt (AdapterInfo, 100);
+ ReNegotiateTime--;
+ }
+
+ //
+ // Read the status register again because of sticky bits
+ //
+ MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
+
+ //
+ // If the link was not set
+ //
+ if ((MdiStatusReg & MDI_SR_LINK_STATUS) == 0) {
+ //
+ // PHY1 does not have a link and phy 0 does not have a link
+ // do not proceed if we need to detect the link!
+ //
+ if (AdapterInfo->CableDetect != 0) {
+ return FALSE;
+ }
+
+ //
+ // the link wasn't set, so use phy 1 if phy 1 was present
+ //
+ if (FoundPhy1) {
+ //
+ // isolate phy 0
+ //
+ MdiWrite (AdapterInfo, MDI_CONTROL_REG, 0, MDI_CR_ISOLATE);
+
+ //
+ // wait 100 microseconds for the phy to isolate.
+ //
+ DelayIt (AdapterInfo, 100);
+
+ //
+ // Now re-enable PHY 1
+ //
+ MdiWrite (
+ AdapterInfo,
+ MDI_CONTROL_REG,
+ AdapterInfo->PhyAddress,
+ MDI_CR_AUTO_SELECT
+ );
+
+ //
+ // wait 100 microseconds for the phy to be enabled
+ //
+ DelayIt (AdapterInfo, 100);
+
+ //
+ // restart the auto-negotion process
+ //
+ MdiWrite (
+ AdapterInfo,
+ MDI_CONTROL_REG,
+ AdapterInfo->PhyAddress,
+ MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT
+ );
+
+ //
+ // Don't wait for it to complete (we didn't have link earlier)
+ //
+ return (SetupPhy (AdapterInfo));
+ }
+ }
+
+ //
+ // Definitely using Phy 0
+ //
+ AdapterInfo->PhyAddress = 0;
+ return (SetupPhy(AdapterInfo));
+ }
+}
+
+BOOLEAN
+SetupPhy (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+ This routine will setup phy 1 or phy 0 so that it is configured
+ to match a speed and duplex over-ride option. If speed or
+ duplex mode is not explicitly specified in the registry, the
+ driver will skip the speed and duplex over-ride code, and
+ assume the adapter is automatically setting the line speed, and
+ the duplex mode. At the end of this routine, any truly Phy
+ specific code will be executed (each Phy has its own quirks,
+ and some require that certain special bits are set).
+
+ NOTE: The driver assumes that SPEED and FORCEFDX are specified at the
+ same time. If FORCEDPX is set without speed being set, the driver
+ will encouter a fatal error and log a message into the event viewer.
+
+Arguments:
+ AdapterInfo - pointer to the structure that contains the NIC's context.
+
+Returns:
+ TRUE - If the phy could be configured correctly
+ FALSE - If the phy couldn't be configured correctly, because an
+ unsupported over-ride option was used
+
+--*/
+{
+ UINT16 MdiControlReg;
+ UINT16 MdiStatusReg;
+ UINT16 MdiIdLowReg;
+ UINT16 MdiIdHighReg;
+ UINT16 MdiMiscReg;
+ UINT32 PhyId;
+ BOOLEAN ForcePhySetting;
+
+ ForcePhySetting = FALSE;
+
+ //
+ // If we are NOT forcing a setting for line speed or full duplex, then
+ // we won't force a link setting, and we'll jump down to the phy
+ // specific code.
+ //
+ if (((AdapterInfo->LinkSpeedReq) || (AdapterInfo->DuplexReq))) {
+ //
+ // Find out what kind of technology this Phy is capable of.
+ //
+ MdiRead (
+ AdapterInfo,
+ MDI_STATUS_REG,
+ AdapterInfo->PhyAddress,
+ &MdiStatusReg
+ );
+
+ //
+ // Read the MDI control register at our phy
+ //
+ MdiRead (
+ AdapterInfo,
+ MDI_CONTROL_REG,
+ AdapterInfo->PhyAddress,
+ &MdiControlReg
+ );
+
+ //
+ // Now check the validity of our forced option. If the force option is
+ // valid, then force the setting. If the force option is not valid,
+ // we'll set a flag indicating that we should error out.
+ //
+
+ //
+ // If speed is forced to 10mb
+ //
+ if (AdapterInfo->LinkSpeedReq == 10) {
+ //
+ // If half duplex is forced
+ //
+ if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) {
+ if (MdiStatusReg & MDI_SR_10T_HALF_DPX) {
+
+ MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
+ ForcePhySetting = TRUE;
+ }
+ } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) {
+
+ //
+ // If full duplex is forced
+ //
+ if (MdiStatusReg & MDI_SR_10T_FULL_DPX) {
+
+ MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT);
+ MdiControlReg |= MDI_CR_FULL_HALF;
+ ForcePhySetting = TRUE;
+ }
+ } else {
+ //
+ // If auto duplex (we actually set phy to 1/2)
+ //
+ if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX)) {
+
+ MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
+ ForcePhySetting = TRUE;
+ }
+ }
+ }
+
+ //
+ // If speed is forced to 100mb
+ //
+ else if (AdapterInfo->LinkSpeedReq == 100) {
+ //
+ // If half duplex is forced
+ //
+ if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) {
+ if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) {
+
+ MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
+ MdiControlReg |= MDI_CR_10_100;
+ ForcePhySetting = TRUE;
+ }
+ } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) {
+ //
+ // If full duplex is forced
+ //
+ if (MdiStatusReg & MDI_SR_TX_FULL_DPX) {
+ MdiControlReg &= ~MDI_CR_AUTO_SELECT;
+ MdiControlReg |= (MDI_CR_10_100 | MDI_CR_FULL_HALF);
+ ForcePhySetting = TRUE;
+ }
+ } else {
+ //
+ // If auto duplex (we set phy to 1/2)
+ //
+ if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) {
+
+ MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
+ MdiControlReg |= MDI_CR_10_100;
+ ForcePhySetting = TRUE;
+ }
+ }
+ }
+
+ if (!ForcePhySetting) {
+ return (FALSE);
+ }
+
+ //
+ // Write the MDI control register with our new Phy configuration
+ //
+ MdiWrite (
+ AdapterInfo,
+ MDI_CONTROL_REG,
+ AdapterInfo->PhyAddress,
+ MdiControlReg
+ );
+
+ //
+ // wait 100 milliseconds for auto-negotiation to complete
+ //
+ DelayIt (AdapterInfo, 100);
+ }
+
+ //
+ // Find out specifically what Phy this is. We do this because for certain
+ // phys there are specific bits that must be set so that the phy and the
+ // 82557 work together properly.
+ //
+
+ MdiRead (
+ AdapterInfo,
+ PHY_ID_REG_1,
+ AdapterInfo->PhyAddress,
+ &MdiIdLowReg
+ );
+ MdiRead (
+ AdapterInfo,
+ PHY_ID_REG_2,
+ AdapterInfo->PhyAddress,
+ &MdiIdHighReg
+ );
+
+ PhyId = ((UINT32) MdiIdLowReg | ((UINT32) MdiIdHighReg << 16));
+
+ //
+ // And out the revsion field of the Phy ID so that we'll be able to detect
+ // future revs of the same Phy.
+ //
+ PhyId &= PHY_MODEL_REV_ID_MASK;
+
+ //
+ // Handle the National TX
+ //
+ if (PhyId == PHY_NSC_TX) {
+
+ MdiRead (
+ AdapterInfo,
+ NSC_CONG_CONTROL_REG,
+ AdapterInfo->PhyAddress,
+ &MdiMiscReg
+ );
+
+ MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT);
+
+#if CONGESTION_CONTROL
+ //
+ // If we are configured to do congestion control, then enable the
+ // congestion control bit in the National Phy
+ //
+ if (AdapterInfo->Congest) {
+ MdiMiscReg |= NSC_TX_CONG_ENABLE;
+ } else {
+ MdiMiscReg &= ~NSC_TX_CONG_ENABLE;
+ }
+#endif
+ MdiWrite (
+ AdapterInfo,
+ NSC_CONG_CONTROL_REG,
+ AdapterInfo->PhyAddress,
+ MdiMiscReg
+ );
+ }
+
+ FindPhySpeedAndDpx (AdapterInfo, PhyId);
+
+ //
+ // We put a hardware fix on to our adapters to work-around the PHY_100 errata
+ // described below. The following code is only compiled in, if we wanted
+ // to attempt a software workaround to the PHY_100 A/B step problem.
+ //
+
+#if DO_PHY_100B_SOFTWARE_FIX
+ //
+ // Handle the Intel PHY_100 (A and B steps)
+ //
+ if ((PhyId == PHY_100_A) && (AdapterInfo->LinkSpeed == 100)) {
+ //
+ // The PHY_100 is very sensitive to collisions at 100mb, so increase
+ // the Adaptive IFS value with the intention of reducing the number of
+ // collisions that the adapter generates.
+ //
+ AdapterInfo->CurrentIFSValue = 0x18;
+ AdapterInfo->AdaptiveIFS = 0;
+ }
+#endif
+
+ return (TRUE);
+}
+
+VOID
+FindPhySpeedAndDpx (
+ IN NIC_DATA_INSTANCE *AdapterInfo,
+ IN UINT32 PhyId
+ )
+/*++
+
+Routine Description:
+ This routine will figure out what line speed and duplex mode
+ the PHY is currently using.
+
+Arguments:
+ AdapterInfo - pointer to the structure that contains the NIC's context.
+ PhyId - The ID of the PHY in question.
+
+Returns:
+ NOTHING
+--*/
+{
+ UINT16 MdiStatusReg;
+ UINT16 MdiMiscReg;
+ UINT16 MdiOwnAdReg;
+ UINT16 MdiLinkPartnerAdReg;
+
+ //
+ // If there was a speed and/or duplex override, then set our current
+ // value accordingly
+ //
+ AdapterInfo->LinkSpeed = AdapterInfo->LinkSpeedReq;
+ AdapterInfo->Duplex = (UINT8) ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) ?
+ FULL_DUPLEX : HALF_DUPLEX);
+
+ //
+ // If speed and duplex were forced, then we know our current settings, so
+ // we'll just return. Otherwise, we'll need to figure out what NWAY set
+ // us to.
+ //
+ if (AdapterInfo->LinkSpeed && AdapterInfo->Duplex) {
+ return ;
+
+ }
+ //
+ // If we didn't have a valid link, then we'll assume that our current
+ // speed is 10mb half-duplex.
+ //
+
+ //
+ // Read the status register twice because of sticky bits
+ //
+ MdiRead (
+ AdapterInfo,
+ MDI_STATUS_REG,
+ AdapterInfo->PhyAddress,
+ &MdiStatusReg
+ );
+ MdiRead (
+ AdapterInfo,
+ MDI_STATUS_REG,
+ AdapterInfo->PhyAddress,
+ &MdiStatusReg
+ );
+
+ //
+ // If there wasn't a valid link then use default speed & duplex
+ //
+ if (!(MdiStatusReg & MDI_SR_LINK_STATUS)) {
+
+ AdapterInfo->LinkSpeed = 10;
+ AdapterInfo->Duplex = HALF_DUPLEX;
+ return ;
+ }
+
+ //
+ // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
+ // 1 and 0 of extended register 0, to get the current speed and duplex
+ // settings.
+ //
+ if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID)) {
+ //
+ // Read extended register 0
+ //
+ MdiRead (
+ AdapterInfo,
+ EXTENDED_REG_0,
+ AdapterInfo->PhyAddress,
+ &MdiMiscReg
+ );
+
+ //
+ // Get current speed setting
+ //
+ if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC) {
+ AdapterInfo->LinkSpeed = 100;
+ } else {
+ AdapterInfo->LinkSpeed = 10;
+ }
+
+ //
+ // Get current duplex setting -- if bit is set then FDX is enabled
+ //
+ if (MdiMiscReg & PHY_100_ER0_FDX_INDIC) {
+ AdapterInfo->Duplex = FULL_DUPLEX;
+ } else {
+ AdapterInfo->Duplex = HALF_DUPLEX;
+ }
+
+ return ;
+ }
+ //
+ // Read our link partner's advertisement register
+ //
+ MdiRead (
+ AdapterInfo,
+ AUTO_NEG_LINK_PARTNER_REG,
+ AdapterInfo->PhyAddress,
+ &MdiLinkPartnerAdReg
+ );
+
+ //
+ // See if Auto-Negotiation was complete (bit 5, reg 1)
+ //
+ MdiRead (
+ AdapterInfo,
+ MDI_STATUS_REG,
+ AdapterInfo->PhyAddress,
+ &MdiStatusReg
+ );
+
+ //
+ // If a True NWAY connection was made, then we can detect speed/duplex by
+ // ANDing our adapter's advertised abilities with our link partner's
+ // advertised ablilities, and then assuming that the highest common
+ // denominator was chosed by NWAY.
+ //
+ if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) &&
+ (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)) {
+
+ //
+ // Read our advertisement register
+ //
+ MdiRead (
+ AdapterInfo,
+ AUTO_NEG_ADVERTISE_REG,
+ AdapterInfo->PhyAddress,
+ &MdiOwnAdReg
+ );
+
+ //
+ // AND the two advertisement registers together, and get rid of any
+ // extraneous bits.
+ //
+ MdiOwnAdReg &= (MdiLinkPartnerAdReg & NWAY_LP_ABILITY);
+
+ //
+ // Get speed setting
+ //
+ if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE)) {
+ AdapterInfo->LinkSpeed = 100;
+ } else {
+ AdapterInfo->LinkSpeed = 10;
+ }
+
+ //
+ // Get duplex setting -- use priority resolution algorithm
+ //
+ if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE)) {
+ AdapterInfo->Duplex = HALF_DUPLEX;
+ return ;
+ } else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX)) {
+ AdapterInfo->Duplex = FULL_DUPLEX;
+ return ;
+ } else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX)) {
+ AdapterInfo->Duplex = HALF_DUPLEX;
+ return ;
+ } else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX)) {
+ AdapterInfo->Duplex = FULL_DUPLEX;
+ return ;
+ } else {
+ AdapterInfo->Duplex = HALF_DUPLEX;
+ return ;
+ }
+ }
+
+ //
+ // If we are connected to a dumb (non-NWAY) repeater or hub, and the line
+ // speed was determined automatically by parallel detection, then we have
+ // no way of knowing exactly what speed the PHY is set to unless that PHY
+ // has a propietary register which indicates speed in this situation. The
+ // NSC TX PHY does have such a register. Also, since NWAY didn't establish
+ // the connection, the duplex setting should HALF duplex.
+ //
+ AdapterInfo->Duplex = HALF_DUPLEX;
+
+ if (PhyId == PHY_NSC_TX) {
+ //
+ // Read register 25 to get the SPEED_10 bit
+ //
+ MdiRead (
+ AdapterInfo,
+ NSC_SPEED_IND_REG,
+ AdapterInfo->PhyAddress,
+ &MdiMiscReg
+ );
+
+ //
+ // If bit 6 was set then we're at 10mb
+ //
+ if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED) {
+ AdapterInfo->LinkSpeed = 10;
+ } else {
+ AdapterInfo->LinkSpeed = 100;
+ }
+ }
+
+ //
+ // If we don't know what line speed we are set at, then we'll default to
+ // 10mbs
+ //
+ else {
+ AdapterInfo->LinkSpeed = 10;
+ }
+}
+
+VOID
+XmitWaitForCompletion (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ TxCB *TxPtr;
+
+ if (AdapterInfo->FreeCBCount == AdapterInfo->TxBufCnt) {
+ return ;
+ }
+
+ //
+ // used xmit cb list starts right after the free tail (ends before the
+ // free head ptr)
+ //
+ TxPtr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr;
+ while (TxPtr != AdapterInfo->FreeTxHeadPtr) {
+ CommandWaitForCompletion (TxPtr, AdapterInfo);
+ SetFreeCB (AdapterInfo, TxPtr);
+ TxPtr = TxPtr->NextTCBVirtualLinkPtr;
+ }
+}
+
+INT8
+CommandWaitForCompletion (
+ TxCB *cmd_ptr,
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ cmd_ptr - TODO: add argument description
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ INT16 wait;
+ wait = 5000;
+ while ((cmd_ptr->cb_header.status == 0) && (--wait > 0)) {
+ DelayIt (AdapterInfo, 10);
+ }
+
+ if (cmd_ptr->cb_header.status == 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+INT8
+SoftwareReset (
+ NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ UINT8 tco_stat;
+ UINT16 wait;
+
+ tco_stat = 0;
+
+ //
+ // Reset the chip: stop Tx and Rx processes and clear counters.
+ // This takes less than 10usec and will easily finish before the next
+ // action.
+ //
+
+ OutLong (AdapterInfo, PORT_RESET, AdapterInfo->ioaddr + SCBPort);
+ //
+ // wait for 5 milli seconds here!
+ //
+ DelayIt (AdapterInfo, 5000);
+ //
+ // TCO Errata work around for 559s only
+ // -----------------------------------------------------------------------------------
+ // TCO Workaround Code
+ // haifa workaround
+ // -----------------------------------------------------------------------------------
+ // 1. Issue SW-RST ^^^ (already done above)
+ // 2. Issue a redundant Set CU Base CMD immediately
+ // Do not set the General Pointer before the Set CU Base cycle
+ // Do not check the SCB CMD before the Set CU Base cycle
+ // 3. Wait for the SCB-CMD to be cleared
+ // this indicates the transition to post-driver
+ // 4. Poll the TCO-Req bit in the PMDR to be cleared
+ // this indicates the tco activity has stopped for real
+ // 5. Proceed with the nominal Driver Init:
+ // Actual Set CU & RU Base ...
+ //
+ // Check for ICH2 device ID. If this is an ICH2,
+ // do the TCO workaround code.
+ //
+ if (AdapterInfo->VendorID == D102_DEVICE_ID ||
+ AdapterInfo->VendorID == ICH3_DEVICE_ID_1 ||
+ AdapterInfo->VendorID == ICH3_DEVICE_ID_2 ||
+ AdapterInfo->VendorID == ICH3_DEVICE_ID_3 ||
+ AdapterInfo->VendorID == ICH3_DEVICE_ID_4 ||
+ AdapterInfo->VendorID == ICH3_DEVICE_ID_5 ||
+ AdapterInfo->VendorID == ICH3_DEVICE_ID_6 ||
+ AdapterInfo->VendorID == ICH3_DEVICE_ID_7 ||
+ AdapterInfo->VendorID == ICH3_DEVICE_ID_8 ||
+ AdapterInfo->RevID >= 8) { // do the TCO fix
+ //
+ // donot load the scb pointer but just give load_cu cmd.
+ //
+ OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd);
+ //
+ // wait for command to be accepted.
+ //
+ wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
+ //
+ // read PMDR register and check bit 1 in it to see if TCO is active
+ //
+
+ //
+ // wait for 5 milli seconds
+ //
+ wait = 5000;
+ while (wait) {
+ tco_stat = InByte (AdapterInfo, AdapterInfo->ioaddr + 0x1b);
+ if ((tco_stat & 2) == 0) {
+ //
+ // is the activity bit clear??
+ //
+ break;
+ }
+
+ wait--;
+ DelayIt (AdapterInfo, 1);
+ }
+
+ if ((tco_stat & 2) != 0) {
+ //
+ // not zero??
+ //
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+UINT8
+SelectiveReset (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ UINT16 wait;
+ UINT32 stat;
+
+ wait = 10;
+ stat = 0;
+ OutLong (AdapterInfo, POR_SELECTIVE_RESET, AdapterInfo->ioaddr + SCBPort);
+ //
+ // wait for this to complete
+ //
+
+ //
+ // wait for 2 milli seconds here!
+ //
+ DelayIt (AdapterInfo, 2000);
+ while (wait > 0) {
+ wait--;
+ stat = InLong (AdapterInfo, AdapterInfo->ioaddr + SCBPort);
+ if (stat == 0) {
+ break;
+ }
+
+ //
+ // wait for 1 milli second
+ //
+ DelayIt (AdapterInfo, 1000);
+ }
+
+ if (stat != 0) {
+ return PXE_STATCODE_DEVICE_FAILURE;
+ }
+
+ return 0;
+}
+
+UINT16
+InitializeChip (
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ AdapterInfo - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ UINT16 ret_val;
+ if (SoftwareReset (AdapterInfo) != 0) {
+ return PXE_STATCODE_DEVICE_FAILURE;
+ }
+
+ //
+ // disable interrupts
+ //
+ OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
+
+ //
+ // Load the base registers with 0s (we will give the complete address as
+ // offset later when we issue any command
+ //
+ if ((ret_val = Load_Base_Regs (AdapterInfo)) != 0) {
+ return ret_val;
+ }
+
+ if ((ret_val = SetupCBlink (AdapterInfo)) != 0) {
+ return ret_val;
+ }
+
+ if ((ret_val = SetupReceiveQueues (AdapterInfo)) != 0) {
+ return ret_val;
+ }
+
+ //
+ // detect the PHY only if we need to detect the cable as requested by the
+ // initialize parameters
+ //
+ AdapterInfo->PhyAddress = 0xFF;
+
+ if (AdapterInfo->CableDetect != 0) {
+ if (!PhyDetect (AdapterInfo)) {
+ return PXE_STATCODE_DEVICE_FAILURE;
+ }
+ }
+
+ if ((ret_val = E100bSetupIAAddr (AdapterInfo)) != 0) {
+ return ret_val;
+ }
+
+ if ((ret_val = Configure (AdapterInfo)) != 0) {
+ return ret_val;
+ }
+
+ return 0;
+}
+
+#pragma data_seg()