audk/MdeModulePkg/Bus/Pci/UndiRuntimeDxe/E100b.c

3757 lines
90 KiB
C

/*++
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_count = 2000; \
while ((InByte (AdapterInfo, cmd_ioaddr) != 0) && --wait_count >= 0) \
DelayIt (AdapterInfo, 10); \
if (wait_count == 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 ;
}
STATIC
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;
}
STATIC
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 ;
}
STATIC
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);
}
}
STATIC
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);
}
}
STATIC
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;
}
STATIC
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;
}
STATIC
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;
volatile 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 = (UINT8) ((my_filter | (AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST) ? 0 : 2));
data_ptr[15] = (UINT8) (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;
}
STATIC
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 ;
}
STATIC
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 = (UINT8) (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 = (UINT16) (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 *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));
}
}
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)
STATIC
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 = (UINT8) (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);
}
}
STATIC
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;
}
STATIC
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;
}
STATIC
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);
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.
//
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 = (UINT16) (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;
}
STATIC
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;
}