windows-nt/Source/XPSP1/NT/drivers/net/ms/e100bex/mp_init.c

2063 lines
62 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
mp_init.c
Abstract:
This module contains miniport initialization related routines
Revision History:
Who When What
-------- -------- ----------------------------------------------
DChen 11-01-99 created
Notes:
--*/
#include "precomp.h"
#if DBG
#define _FILENUMBER 'TINI'
#endif
typedef struct _MP_REG_ENTRY
{
NDIS_STRING RegName; // variable name text
BOOLEAN bRequired; // 1 -> required, 0 -> optional
UINT FieldOffset; // offset to MP_ADAPTER field
UINT FieldSize; // size (in bytes) of the field
UINT Default; // default value to use
UINT Min; // minimum value allowed
UINT Max; // maximum value allowed
} MP_REG_ENTRY, *PMP_REG_ENTRY;
MP_REG_ENTRY NICRegTable[] = {
// reg value name Offset in MP_ADAPTER Field size Default Value Min Max
#if DBG
{NDIS_STRING_CONST("Debug"), 0, MP_OFFSET(Debug), MP_SIZE(Debug), MP_WARN, 0, 0xffffffff},
#endif
{NDIS_STRING_CONST("NumRfd"), 0, MP_OFFSET(NumRfd), MP_SIZE(NumRfd), 32, NIC_MIN_RFDS, NIC_MAX_RFDS},
{NDIS_STRING_CONST("NumTcb"), 0, MP_OFFSET(NumTcb), MP_SIZE(NumTcb), NIC_DEF_TCBS, 1, NIC_MAX_TCBS},
{NDIS_STRING_CONST("NumCoalesce"), 0, MP_OFFSET(NumBuffers), MP_SIZE(NumBuffers), 8, 1, 32},
{NDIS_STRING_CONST("PhyAddress"), 0, MP_OFFSET(PhyAddress), MP_SIZE(PhyAddress), 0xFF, 0, 0xFF},
{NDIS_STRING_CONST("Connector"), 0, MP_OFFSET(Connector), MP_SIZE(Connector), 0, 0, 0x2},
{NDIS_STRING_CONST("TxFifo"), 0, MP_OFFSET(AiTxFifo), MP_SIZE(AiTxFifo), DEFAULT_TX_FIFO_LIMIT, 0, 15},
{NDIS_STRING_CONST("RxFifo"), 0, MP_OFFSET(AiRxFifo), MP_SIZE(AiRxFifo), DEFAULT_RX_FIFO_LIMIT, 0, 15},
{NDIS_STRING_CONST("TxDmaCount"), 0, MP_OFFSET(AiTxDmaCount), MP_SIZE(AiTxDmaCount), 0, 0, 63},
{NDIS_STRING_CONST("RxDmaCount"), 0, MP_OFFSET(AiRxDmaCount), MP_SIZE(AiRxDmaCount), 0, 0, 63},
{NDIS_STRING_CONST("UnderrunRetry"), 0, MP_OFFSET(AiUnderrunRetry), MP_SIZE(AiUnderrunRetry), DEFAULT_UNDERRUN_RETRY, 0, 3},
{NDIS_STRING_CONST("Threshold"), 0, MP_OFFSET(AiThreshold), MP_SIZE(AiThreshold), 200, 0, 200},
{NDIS_STRING_CONST("MWIEnable"), 0, MP_OFFSET(MWIEnable), MP_SIZE(MWIEnable), 1, 0, 1},
{NDIS_STRING_CONST("Congest"), 0, MP_OFFSET(Congest), MP_SIZE(Congest), 0, 0, 0x1},
{NDIS_STRING_CONST("SpeedDuplex"), 0, MP_OFFSET(SpeedDuplex), MP_SIZE(SpeedDuplex), 0, 0, 4}
};
#define NIC_NUM_REG_PARAMS (sizeof (NICRegTable) / sizeof(MP_REG_ENTRY))
#if LBFO
NDIS_STRING strBundleId = NDIS_STRING_CONST("BundleId");
#endif
NDIS_STATUS MpFindAdapter(
IN PMP_ADAPTER Adapter,
IN NDIS_HANDLE WrapperConfigurationContext
)
/*++
Routine Description:
Find the adapter and get all the assigned resources
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_ADAPTER_NOT_FOUND (event is logged as well)
--*/
{
#define NIC_PCI_E100_HDR_LENGTH 0xe2
NDIS_STATUS Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
ULONG ErrorCode;
ULONG ErrorValue;
ULONG ulResult;
UCHAR buffer[NIC_PCI_E100_HDR_LENGTH ];
PPCI_COMMON_CONFIG pPciConfig = (PPCI_COMMON_CONFIG) buffer;
USHORT usPciCommand;
UCHAR resBuf[NIC_RESOURCE_BUF_SIZE];
PNDIS_RESOURCE_LIST resList = (PNDIS_RESOURCE_LIST)resBuf;
UINT bufSize = NIC_RESOURCE_BUF_SIZE;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc;
ULONG index;
BOOLEAN bResPort = FALSE, bResInterrupt = FALSE, bResMemory = FALSE;
DBGPRINT(MP_TRACE, ("---> MpFindAdapter\n"));
do
{
//
// Find our adapter - read in the device and vendor IDs
//
ulResult = NdisReadPciSlotInformation(
Adapter->AdapterHandle,
0, // not used
FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID),
buffer,
NIC_PCI_E100_HDR_LENGTH );
if (ulResult != NIC_PCI_E100_HDR_LENGTH )
{
DBGPRINT(MP_ERROR,
("NdisReadPciSlotInformation (PCI_COMMON_CONFIG) ulResult=%d\n", ulResult));
ErrorCode = NDIS_ERROR_CODE_ADAPTER_NOT_FOUND;
ErrorValue = ERRLOG_READ_PCI_SLOT_FAILED;
break;
}
//
// Right type of adapter?
//
if (pPciConfig->VendorID != NIC_PCI_VENDOR_ID ||
pPciConfig->DeviceID != NIC_PCI_DEVICE_ID)
{
DBGPRINT(MP_ERROR, ("VendorID/DeviceID don't match - %x/%x\n",
pPciConfig->VendorID, pPciConfig->DeviceID));
ErrorCode = NDIS_ERROR_CODE_ADAPTER_NOT_FOUND;
ErrorValue = ERRLOG_VENDOR_DEVICE_NOMATCH;
break;
}
DBGPRINT(MP_INFO, ("Adapter is found - VendorID/DeviceID=%x/%x\n",
pPciConfig->VendorID, pPciConfig->DeviceID));
// save info from config space
Adapter->RevsionID = pPciConfig->RevisionID;
Adapter->SubVendorID = pPciConfig->u.type0.SubVendorID;
Adapter->SubSystemID = pPciConfig->u.type0.SubSystemID;
MpExtractPMInfoFromPciSpace (Adapter, (PUCHAR)pPciConfig);
// --- HW_START
usPciCommand = pPciConfig->Command;
if ((usPciCommand & PCI_ENABLE_WRITE_AND_INVALIDATE) && (Adapter->MWIEnable))
Adapter->MWIEnable = TRUE;
else
Adapter->MWIEnable = FALSE;
// Enable bus matering if it isn't enabled by the BIOS
if (!(usPciCommand & PCI_ENABLE_BUS_MASTER))
{
DBGPRINT(MP_WARN, ("Bus master is not enabled by BIOS! usPciCommand=%x\n",
usPciCommand));
usPciCommand |= CMD_BUS_MASTER;
ulResult = NdisWritePciSlotInformation(
Adapter->AdapterHandle,
0,
FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
&usPciCommand,
sizeof(USHORT));
if (ulResult != sizeof(USHORT))
{
DBGPRINT(MP_ERROR,
("NdisWritePciSlotInformation (Command) ulResult=%d\n", ulResult));
ErrorCode = NDIS_ERROR_CODE_ADAPTER_NOT_FOUND;
ErrorValue = ERRLOG_WRITE_PCI_SLOT_FAILED;
break;
}
ulResult = NdisReadPciSlotInformation(
Adapter->AdapterHandle,
0,
FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
&usPciCommand,
sizeof(USHORT));
if (ulResult != sizeof(USHORT))
{
DBGPRINT(MP_ERROR,
("NdisReadPciSlotInformation (Command) ulResult=%d\n", ulResult));
ErrorCode = NDIS_ERROR_CODE_ADAPTER_NOT_FOUND;
ErrorValue = ERRLOG_READ_PCI_SLOT_FAILED;
break;
}
if (!(usPciCommand & PCI_ENABLE_BUS_MASTER))
{
DBGPRINT(MP_ERROR, ("Failed to enable bus master! usPciCommand=%x\n",
usPciCommand));
ErrorCode = NDIS_ERROR_CODE_ADAPTER_DISABLED;
ErrorValue = ERRLOG_BUS_MASTER_DISABLED;
break;
}
}
DBGPRINT(MP_INFO, ("Bus master is enabled. usPciCommand=%x\n", usPciCommand));
// --- HW_END
//
// Adapter is found. Now get the assigned resources
//
NdisMQueryAdapterResources(
&Status,
WrapperConfigurationContext,
resList,
&bufSize);
if (Status != NDIS_STATUS_SUCCESS)
{
ErrorCode = NDIS_ERROR_CODE_RESOURCE_CONFLICT;
ErrorValue = ERRLOG_QUERY_ADAPTER_RESOURCES;
break;
}
for (index=0; index < resList->Count; index++)
{
pResDesc = &resList->PartialDescriptors[index];
switch(pResDesc->Type)
{
case CmResourceTypePort:
Adapter->IoBaseAddress = NdisGetPhysicalAddressLow(pResDesc->u.Port.Start);
Adapter->IoRange = pResDesc->u.Port.Length;
bResPort = TRUE;
DBGPRINT(MP_INFO, ("IoBaseAddress = 0x%x\n", Adapter->IoBaseAddress));
DBGPRINT(MP_INFO, ("IoRange = x%x\n", Adapter->IoRange));
break;
case CmResourceTypeInterrupt:
Adapter->InterruptLevel = pResDesc->u.Interrupt.Level;
bResInterrupt = TRUE;
DBGPRINT(MP_INFO, ("InterruptLevel = x%x\n", Adapter->InterruptLevel));
break;
case CmResourceTypeMemory:
// Our CSR memory space should be 0x1000, other memory is for
// flash address, a boot ROM address, etc.
if (pResDesc->u.Memory.Length == 0x1000)
{
Adapter->MemPhysAddress = pResDesc->u.Memory.Start;
bResMemory = TRUE;
DBGPRINT(MP_INFO,
("MemPhysAddress(Low) = 0x%0x\n", NdisGetPhysicalAddressLow(Adapter->MemPhysAddress)));
DBGPRINT(MP_INFO,
("MemPhysAddress(High) = 0x%0x\n", NdisGetPhysicalAddressHigh(Adapter->MemPhysAddress)));
}
break;
}
}
if (!bResPort || !bResInterrupt || !bResMemory)
{
Status = NDIS_STATUS_RESOURCE_CONFLICT;
ErrorCode = NDIS_ERROR_CODE_RESOURCE_CONFLICT;
if (!bResPort)
{
ErrorValue = ERRLOG_NO_IO_RESOURCE;
}
else if (!bResInterrupt)
{
ErrorValue = ERRLOG_NO_INTERRUPT_RESOURCE;
}
else
{
ErrorValue = ERRLOG_NO_MEMORY_RESOURCE;
}
break;
}
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
if (Status != NDIS_STATUS_SUCCESS)
{
NdisWriteErrorLogEntry(
Adapter->AdapterHandle,
ErrorCode,
1,
ErrorValue);
}
DBGPRINT_S(Status, ("<--- MpFindAdapter, Status=%x\n", Status));
return Status;
}
NDIS_STATUS NICReadAdapterInfo(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Read the mac addresss from the adapter
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_INVALID_ADDRESS
--*/
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
USHORT usValue;
int i;
DBGPRINT(MP_TRACE, ("--> NICReadAdapterInfo\n"));
Adapter->EepromAddressSize =
GetEEpromAddressSize(GetEEpromSize(Adapter->PortOffset));
DBGPRINT(MP_WARN, ("EepromAddressSize = %d\n", Adapter->EepromAddressSize));
// Read node address from the EEPROM
for (i=0; i<6; i += 2)
{
usValue = ReadEEprom(Adapter->PortOffset,
(USHORT)(EEPROM_NODE_ADDRESS_BYTE_0 + (i/2)),
Adapter->EepromAddressSize);
*((PUSHORT)(&Adapter->PermanentAddress[i])) = usValue;
}
DBGPRINT(MP_INFO, ("Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
Adapter->PermanentAddress[0], Adapter->PermanentAddress[1],
Adapter->PermanentAddress[2], Adapter->PermanentAddress[3],
Adapter->PermanentAddress[4], Adapter->PermanentAddress[5]));
if (ETH_IS_MULTICAST(Adapter->PermanentAddress) ||
ETH_IS_BROADCAST(Adapter->PermanentAddress))
{
DBGPRINT(MP_ERROR, ("Permanent address is invalid\n"));
NdisWriteErrorLogEntry(
Adapter->AdapterHandle,
NDIS_ERROR_CODE_NETWORK_ADDRESS,
0);
Status = NDIS_STATUS_INVALID_ADDRESS;
}
else
{
if (!Adapter->bOverrideAddress)
{
ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentAddress, Adapter->PermanentAddress);
}
DBGPRINT(MP_INFO, ("Current Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
Adapter->CurrentAddress[0], Adapter->CurrentAddress[1],
Adapter->CurrentAddress[2], Adapter->CurrentAddress[3],
Adapter->CurrentAddress[4], Adapter->CurrentAddress[5]));
}
DBGPRINT_S(Status, ("<-- NICReadAdapterInfo, Status=%x\n", Status));
return Status;
}
NDIS_STATUS MpAllocAdapterBlock(
OUT PMP_ADAPTER *pAdapter)
/*++
Routine Description:
Allocate MP_ADAPTER data block and do some initialization
Arguments:
Adapter Pointer to receive pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_FAILURE
--*/
{
PMP_ADAPTER Adapter;
NDIS_HANDLE PacketPoolHandle;
NDIS_HANDLE BufferPoolHandle;
PNDIS_PACKET Packet;
PNDIS_BUFFER Buffer;
NDIS_STATUS Status;
LONG index;
DBGPRINT(MP_TRACE, ("--> NICAllocAdapter\n"));
*pAdapter = NULL;
do
{
// Allocate MP_ADAPTER block
Status = MP_ALLOCMEMTAG(&Adapter, sizeof(MP_ADAPTER));
if (Status != NDIS_STATUS_SUCCESS)
{
DBGPRINT(MP_ERROR, ("Failed to allocate memory - ADAPTER\n"));
break;
}
// Clean up the memory block
NdisZeroMemory(Adapter, sizeof(MP_ADAPTER));
MP_INC_REF(Adapter);
// Init lists, spinlocks, etc.
InitializeQueueHeader(&Adapter->SendWaitQueue);
InitializeQueueHeader(&Adapter->SendCancelQueue);
InitializeListHead(&Adapter->RecvList);
InitializeListHead(&Adapter->RecvPendList);
InitializeListHead(&Adapter->PoMgmt.PatternList);
NdisInitializeEvent(&Adapter->ExitEvent);
NdisInitializeEvent(&Adapter->AllPacketsReturnedEvent);
MP_INC_RCV_REF(Adapter);
NdisAllocateSpinLock(&Adapter->Lock);
NdisAllocateSpinLock(&Adapter->SendLock);
NdisAllocateSpinLock(&Adapter->RcvLock);
} while (FALSE);
*pAdapter = Adapter;
DBGPRINT_S(Status, ("<-- NICAllocAdapter, Status=%x\n", Status));
return Status;
}
VOID MpFreeAdapter(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Free all the resources and MP_ADAPTER data block
Arguments:
Adapter Pointer to our adapter
Return Value:
None
--*/
{
PMP_TXBUF pMpTxBuf;
PMP_RFD pMpRfd;
DBGPRINT(MP_TRACE, ("--> NICFreeAdapter\n"));
// No active and waiting sends
ASSERT(Adapter->nBusySend == 0);
ASSERT(Adapter->nWaitSend == 0);
ASSERT(IsQueueEmpty(&Adapter->SendWaitQueue));
ASSERT(IsQueueEmpty(&Adapter->SendCancelQueue));
// No other pending operations
ASSERT(IsListEmpty(&Adapter->RecvPendList));
ASSERT(Adapter->bAllocNewRfd == FALSE);
ASSERT(!MP_TEST_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION));
ASSERT(MP_GET_REF(Adapter) == 0);
//
// Free hardware resources
//
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_INTERRUPT_IN_USE))
{
NdisMDeregisterInterrupt(&Adapter->Interrupt);
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_INTERRUPT_IN_USE);
}
if (Adapter->CSRAddress)
{
NdisMUnmapIoSpace(
Adapter->AdapterHandle,
Adapter->CSRAddress,
NIC_MAP_IOSPACE_LENGTH);
Adapter->CSRAddress = NULL;
}
if (Adapter->PortOffset)
{
NdisMDeregisterIoPortRange(
Adapter->AdapterHandle,
Adapter->IoBaseAddress,
Adapter->IoRange,
Adapter->PortOffset);
Adapter->PortOffset = NULL;
}
//
// Free RECV memory/NDIS buffer/NDIS packets/shared memory
//
ASSERT(Adapter->nReadyRecv == Adapter->CurrNumRfd);
while (!IsListEmpty(&Adapter->RecvList))
{
pMpRfd = (PMP_RFD)RemoveHeadList(&Adapter->RecvList);
NICFreeRfd(Adapter, pMpRfd);
}
// Free receive buffer pool
if (Adapter->RecvBufferPool)
{
NdisFreeBufferPool(Adapter->RecvBufferPool);
Adapter->RecvBufferPool = NULL;
}
// Free receive packet pool
if (Adapter->RecvPacketPool)
{
NdisFreePacketPool(Adapter->RecvPacketPool);
Adapter->RecvPacketPool = NULL;
}
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_RECV_LOOKASIDE))
{
NdisDeleteNPagedLookasideList(&Adapter->RecvLookaside);
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_RECV_LOOKASIDE);
}
//
// Free SEND memory/NDIS buffer/NDIS packets/shared memory
//
while (!IsSListEmpty(&Adapter->SendBufList))
{
pMpTxBuf = (PMP_TXBUF)PopEntryList(&Adapter->SendBufList);
ASSERT(pMpTxBuf);
// Free the shared memory associated with each MP_TXBUF
if (pMpTxBuf->AllocVa)
{
NdisMFreeSharedMemory(
Adapter->AdapterHandle,
pMpTxBuf->AllocSize,
TRUE,
pMpTxBuf->AllocVa,
pMpTxBuf->AllocPa);
pMpTxBuf->AllocVa = NULL;
}
// Free the NDIS buffer
if (pMpTxBuf->NdisBuffer)
{
NdisFreeBuffer(pMpTxBuf->NdisBuffer);
pMpTxBuf->NdisBuffer = NULL;
}
}
// Free the send buffer pool
if (Adapter->SendBufferPool)
{
NdisFreeBufferPool(Adapter->SendBufferPool);
Adapter->SendBufferPool = NULL;
}
// Free the memory for MP_TXBUF structures
if (Adapter->MpTxBufMem)
{
MP_FREEMEM(Adapter->MpTxBufMem, Adapter->MpTxBufMemSize, 0);
Adapter->MpTxBufMem = NULL;
}
// Free the shared memory for HW_TCB structures
if (Adapter->HwSendMemAllocVa)
{
NdisMFreeSharedMemory(
Adapter->AdapterHandle,
Adapter->HwSendMemAllocSize,
FALSE,
Adapter->HwSendMemAllocVa,
Adapter->HwSendMemAllocPa);
Adapter->HwSendMemAllocVa = NULL;
}
// Free the shared memory for other command data structures
if (Adapter->HwMiscMemAllocVa)
{
NdisMFreeSharedMemory(
Adapter->AdapterHandle,
Adapter->HwMiscMemAllocSize,
FALSE,
Adapter->HwMiscMemAllocVa,
Adapter->HwMiscMemAllocPa);
Adapter->HwMiscMemAllocVa = NULL;
}
// Free the memory for MP_TCB structures
if (Adapter->MpTcbMem)
{
MP_FREEMEM(Adapter->MpTcbMem, Adapter->MpTcbMemSize, 0);
Adapter->MpTcbMem = NULL;
}
// Free map registers. This must be after all the shared memory is freed
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_MAP_REGISTER))
{
NdisMFreeMapRegisters(Adapter->AdapterHandle);
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_MAP_REGISTER);
}
//Free all the wake up patterns on this adapter
MPRemoveAllWakeUpPatterns(Adapter);
NdisFreeSpinLock(&Adapter->Lock);
#if LBFO
if (Adapter->BundleId.MaximumLength)
{
MP_FREE_NDIS_STRING(&Adapter->BundleId);
}
#endif
#if OFFLOAD
// Free the shared memory for offload tasks
if (Adapter->OffloadSharedMem.StartVa)
{
NdisMFreeSharedMemory(
Adapter->AdapterHandle,
Adapter->OffloadSharedMemSize,
FALSE,
Adapter->OffloadSharedMem.StartVa,
Adapter->OffloadSharedMem.PhyAddr);
Adapter->OffloadSharedMem.StartVa = NULL;
}
#endif
MP_FREEMEM(Adapter, sizeof(MP_ADAPTER), 0);
DBGPRINT(MP_TRACE, ("<-- NICFreeAdapter\n"));
}
NDIS_STATUS NICReadRegParameters(
IN PMP_ADAPTER Adapter,
IN NDIS_HANDLE WrapperConfigurationContext)
/*++
Routine Description:
Read the following from the registry
1. All the parameters
2. NetworkAddres
3. LBFO - BundleId
Arguments:
Adapter Pointer to our adapter
WrapperConfigurationContext For use by NdisOpenConfiguration
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_FAILURE
NDIS_STATUS_RESOURCES
--*/
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NDIS_HANDLE ConfigurationHandle;
PMP_REG_ENTRY pRegEntry;
UINT i;
UINT value;
PUCHAR pointer;
PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
PUCHAR NetworkAddress;
UINT Length;
DBGPRINT(MP_TRACE, ("--> NICReadRegParameters\n"));
// Open the registry for this adapter
NdisOpenConfiguration(
&Status,
&ConfigurationHandle,
WrapperConfigurationContext);
if (Status != NDIS_STATUS_SUCCESS)
{
DBGPRINT(MP_ERROR, ("NdisOpenConfiguration failed\n"));
DBGPRINT_S(Status, ("<-- NICReadRegParameters, Status=%x\n", Status));
return Status;
}
// read all the registry values
for (i = 0, pRegEntry = NICRegTable; i < NIC_NUM_REG_PARAMS; i++, pRegEntry++)
{
pointer = (PUCHAR) Adapter + pRegEntry->FieldOffset;
DBGPRINT_UNICODE(MP_INFO, &pRegEntry->RegName);
// Get the configuration value for a specific parameter. Under NT the
// parameters are all read in as DWORDs.
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigurationHandle,
&pRegEntry->RegName,
NdisParameterInteger);
// If the parameter was present, then check its value for validity.
if (Status == NDIS_STATUS_SUCCESS)
{
// Check that param value is not too small or too large
if (ReturnedValue->ParameterData.IntegerData < pRegEntry->Min ||
ReturnedValue->ParameterData.IntegerData > pRegEntry->Max)
{
value = pRegEntry->Default;
}
else
{
value = ReturnedValue->ParameterData.IntegerData;
}
DBGPRINT_RAW(MP_INFO, ("= 0x%x\n", value));
}
else if (pRegEntry->bRequired)
{
DBGPRINT_RAW(MP_ERROR, (" -- failed\n"));
ASSERT(FALSE);
Status = NDIS_STATUS_FAILURE;
break;
}
else
{
value = pRegEntry->Default;
DBGPRINT_RAW(MP_INFO, ("= 0x%x (default)\n", value));
Status = NDIS_STATUS_SUCCESS;
}
// Store the value in the adapter structure.
switch(pRegEntry->FieldSize)
{
case 1:
*((PUCHAR) pointer) = (UCHAR) value;
break;
case 2:
*((PUSHORT) pointer) = (USHORT) value;
break;
case 4:
*((PULONG) pointer) = (ULONG) value;
break;
default:
DBGPRINT(MP_ERROR, ("Bogus field size %d\n", pRegEntry->FieldSize));
break;
}
}
// Read NetworkAddress registry value
// Use it as the current address if any
if (Status == NDIS_STATUS_SUCCESS)
{
NdisReadNetworkAddress(
&Status,
&NetworkAddress,
&Length,
ConfigurationHandle);
// If there is a NetworkAddress override in registry, use it
if ((Status == NDIS_STATUS_SUCCESS) && (Length == ETH_LENGTH_OF_ADDRESS))
{
if (ETH_IS_MULTICAST(NetworkAddress) || ETH_IS_BROADCAST(NetworkAddress))
{
DBGPRINT(MP_ERROR,
("Overriding NetworkAddress is invalid - %02x-%02x-%02x-%02x-%02x-%02x\n",
NetworkAddress[0], NetworkAddress[1], NetworkAddress[2],
NetworkAddress[3], NetworkAddress[4], NetworkAddress[5]));
}
else
{
ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentAddress, NetworkAddress);
Adapter->bOverrideAddress = TRUE;
}
}
Status = NDIS_STATUS_SUCCESS;
}
#if LBFO
if (Status == NDIS_STATUS_SUCCESS)
{
// Read BundleIdentifier string
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigurationHandle,
&strBundleId,
NdisParameterString);
if (Status == NDIS_STATUS_SUCCESS)
{
ASSERT(ReturnedValue->ParameterType == NdisParameterString);
if (ReturnedValue->ParameterData.StringData.Length !=0)
{
Status = MP_ALLOCMEMTAG(&Adapter->BundleId.Buffer,
ReturnedValue->ParameterData.StringData.Length + sizeof(WCHAR));
if (Status == NDIS_STATUS_SUCCESS)
{
Adapter->BundleId.MaximumLength =
ReturnedValue->ParameterData.StringData.Length + sizeof(WCHAR);
NdisUpcaseUnicodeString(
&Adapter->BundleId,
&ReturnedValue->ParameterData.StringData);
}
else
{
DBGPRINT(MP_ERROR, ("Failed to allocate memory - BundleIdentifier\n"));
}
}
}
else
{
// This parameter is optional, set status to SUCCESS
Status = NDIS_STATUS_SUCCESS;
}
}
#endif
// Close the registry
NdisCloseConfiguration(ConfigurationHandle);
// Decode SpeedDuplex
if (Status == NDIS_STATUS_SUCCESS && Adapter->SpeedDuplex)
{
switch(Adapter->SpeedDuplex)
{
case 1:
Adapter->AiTempSpeed = 10; Adapter->AiForceDpx = 1;
break;
case 2:
Adapter->AiTempSpeed = 10; Adapter->AiForceDpx = 2;
break;
case 3:
Adapter->AiTempSpeed = 100; Adapter->AiForceDpx = 1;
break;
case 4:
Adapter->AiTempSpeed = 100; Adapter->AiForceDpx = 2;
break;
}
}
DBGPRINT_S(Status, ("<-- NICReadRegParameters, Status=%x\n", Status));
return Status;
}
NDIS_STATUS NICAllocAdapterMemory(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Allocate all the memory blocks for send, receive and others
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_FAILURE
NDIS_STATUS_RESOURCES
--*/
{
NDIS_STATUS Status;
PMP_TCB pMpTCB;
PMP_TXBUF pMpTxbuf;
PUCHAR pMem;
ULONG MemPhys;
LONG index;
LONG MapRegisterCount;
ULONG ErrorValue = 0;
UINT MaxNumBuffers;
#if OFFLOAD
BOOLEAN OffloadSharedMemSuccess = FALSE;
UINT i;
#endif
DBGPRINT(MP_TRACE, ("--> NICAllocMemory\n"));
DBGPRINT(MP_INFO, ("NumTcb=%d\n", Adapter->NumTcb));
Adapter->NumTbd = Adapter->NumTcb * NIC_MAX_PHYS_BUF_COUNT;
do
{
//
// Try to use the ScatterGather method first, this is the preferred way
// Only use map registers if we can't do scatter gather (e.g. on win9x)
#if OFFLOAD
Status = NdisMInitializeScatterGatherDma(
Adapter->AdapterHandle,
FALSE,
LARGE_SEND_OFFLOAD_SIZE);
#else
Status = NdisMInitializeScatterGatherDma(
Adapter->AdapterHandle,
FALSE,
NIC_MAX_PACKET_SIZE);
#endif
if (Status == NDIS_STATUS_SUCCESS)
{
MP_SET_FLAG(Adapter, fMP_ADAPTER_SCATTER_GATHER);
}
else
{
DBGPRINT(MP_WARN, ("Failed to init ScatterGather DMA, allocate map registers\n"));
// We should limit the totoal map registers needed to 32
Adapter->NumTcb = 32 / NIC_MAX_PHYS_BUF_COUNT;
Adapter->NumTbd = Adapter->NumTcb * NIC_MAX_PHYS_BUF_COUNT;
DBGPRINT(MP_WARN, ("NumTcb is reduced to %d", Adapter->NumTcb));
while (Adapter->NumTcb > 0)
{
Status = NdisMAllocateMapRegisters(
Adapter->AdapterHandle,
0,
NDIS_DMA_32BITS,
Adapter->NumTbd,
NIC_MAX_PACKET_SIZE);
if (Status == NDIS_STATUS_SUCCESS)
{
break;
}
// Reduce NumTcb and try again
Adapter->NumTcb--;
DBGPRINT(MP_WARN, ("NumTcb is reduced to %d", Adapter->NumTcb));
Adapter->NumTbd = Adapter->NumTcb * NIC_MAX_PHYS_BUF_COUNT;
}
if (Status == NDIS_STATUS_SUCCESS)
{
MP_SET_FLAG(Adapter, fMP_ADAPTER_MAP_REGISTER);
}
else
{
ErrorValue = ERRLOG_OUT_OF_MAP_REGISTERS;
DBGPRINT(MP_ERROR, ("Failed to allocate map registers\n"));
break;
}
}
//
// Send + Misc
//
//
// Allocate MP_TCB's
//
Adapter->MpTcbMemSize = Adapter->NumTcb * sizeof(MP_TCB);
Status = MP_ALLOCMEMTAG(&pMem, Adapter->MpTcbMemSize);
if (Status != NDIS_STATUS_SUCCESS)
{
ErrorValue = ERRLOG_OUT_OF_MEMORY;
DBGPRINT(MP_ERROR, ("Failed to allocate MP_TCB's\n"));
break;
}
NdisZeroMemory(pMem, Adapter->MpTcbMemSize);
Adapter->MpTcbMem = pMem;
//
// Now the driver needs to allocate send buffer pool, the number
// of send buffers the driver needs is the larger one of Adapter->NumBuffer
// and Adapter->NumTcb.
//
MaxNumBuffers = Adapter->NumBuffers > Adapter->NumTcb ? Adapter->NumBuffers: Adapter->NumTcb;
NdisAllocateBufferPool(
&Status,
&Adapter->SendBufferPool,
MaxNumBuffers);
if (Status != NDIS_STATUS_SUCCESS)
{
ErrorValue = ERRLOG_OUT_OF_BUFFER_POOL;
DBGPRINT(MP_ERROR, ("Failed to allocate send buffer pool\n"));
break;
}
// Allocate send buffers
Adapter->MpTxBufMemSize = Adapter->NumBuffers * sizeof(MP_TXBUF);
Status = MP_ALLOCMEMTAG(&pMem, Adapter->MpTxBufMemSize);
if (Status != NDIS_STATUS_SUCCESS)
{
ErrorValue = ERRLOG_OUT_OF_MEMORY;
DBGPRINT(MP_ERROR, ("Failed to allocate MP_TXBUF's\n"));
break;
}
NdisZeroMemory(pMem, Adapter->MpTxBufMemSize);
Adapter->MpTxBufMem = pMem;
pMpTxbuf = (PMP_TXBUF) pMem;
//
// NdisMGetDmaAlignment is provided in XP (WINVER=0x0501) and higher
// if you need to write a driver that runs on older versions of Windows
// you need to compile with older versions of DDK which have WINVER < 0x0501
// such as W2K DDK.
//
#if (WINVER < 0x0501)
Adapter->CacheFillSize = NdisGetCacheFillSize();
#else
Adapter->CacheFillSize = NdisMGetDmaAlignment(Adapter->AdapterHandle);
#endif
DBGPRINT(MP_INFO, ("CacheFillSize=%d\n", Adapter->CacheFillSize));
for (index = 0; index < Adapter->NumBuffers; index++)
{
pMpTxbuf->AllocSize = NIC_MAX_PACKET_SIZE + Adapter->CacheFillSize;
pMpTxbuf->BufferSize = NIC_MAX_PACKET_SIZE;
NdisMAllocateSharedMemory(
Adapter->AdapterHandle,
pMpTxbuf->AllocSize,
TRUE, // CACHED
&pMpTxbuf->AllocVa,
&pMpTxbuf->AllocPa);
if (!pMpTxbuf->AllocVa)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
DBGPRINT(MP_ERROR, ("Failed to allocate a big buffer\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
// Align the buffer on the cache line boundary
pMpTxbuf->pBuffer = MP_ALIGNMEM(pMpTxbuf->AllocVa, Adapter->CacheFillSize);
pMpTxbuf->BufferPa.QuadPart = MP_ALIGNMEM_PA(pMpTxbuf->AllocPa, Adapter->CacheFillSize);
NdisAllocateBuffer(
&Status,
&pMpTxbuf->NdisBuffer,
Adapter->SendBufferPool,
pMpTxbuf->pBuffer,
pMpTxbuf->BufferSize);
if (Status != NDIS_STATUS_SUCCESS)
{
ErrorValue = ERRLOG_OUT_OF_NDIS_BUFFER;
DBGPRINT(MP_ERROR, ("Failed to allocate NDIS buffer for a big buffer\n"));
NdisMFreeSharedMemory(
Adapter->AdapterHandle,
pMpTxbuf->AllocSize,
TRUE, // CACHED
pMpTxbuf->AllocVa,
pMpTxbuf->AllocPa);
break;
}
PushEntryList(&Adapter->SendBufList, &pMpTxbuf->SList);
pMpTxbuf++;
}
if (Status != NDIS_STATUS_SUCCESS) break;
// HW_START
// Allocate shared memory for send
Adapter->HwSendMemAllocSize = Adapter->NumTcb * (sizeof(TXCB_STRUC) +
NIC_MAX_PHYS_BUF_COUNT * sizeof(TBD_STRUC));
NdisMAllocateSharedMemory(
Adapter->AdapterHandle,
Adapter->HwSendMemAllocSize,
FALSE,
(PVOID) &Adapter->HwSendMemAllocVa,
&Adapter->HwSendMemAllocPa);
if (!Adapter->HwSendMemAllocVa)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
DBGPRINT(MP_ERROR, ("Failed to allocate send memory\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
NdisZeroMemory(Adapter->HwSendMemAllocVa, Adapter->HwSendMemAllocSize);
// Allocate shared memory for other uses
Adapter->HwMiscMemAllocSize =
sizeof(SELF_TEST_STRUC) + ALIGN_16 +
sizeof(DUMP_AREA_STRUC) + ALIGN_16 +
sizeof(NON_TRANSMIT_CB) + ALIGN_16 +
sizeof(ERR_COUNT_STRUC) + ALIGN_16;
// Allocate the shared memory for the command block data structures.
NdisMAllocateSharedMemory(
Adapter->AdapterHandle,
Adapter->HwMiscMemAllocSize,
FALSE,
(PVOID *) &Adapter->HwMiscMemAllocVa,
&Adapter->HwMiscMemAllocPa);
if (!Adapter->HwMiscMemAllocVa)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
DBGPRINT(MP_ERROR, ("Failed to allocate misc memory\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
NdisZeroMemory(Adapter->HwMiscMemAllocVa, Adapter->HwMiscMemAllocSize);
pMem = Adapter->HwMiscMemAllocVa;
MemPhys = NdisGetPhysicalAddressLow(Adapter->HwMiscMemAllocPa);
Adapter->SelfTest = (PSELF_TEST_STRUC)MP_ALIGNMEM(pMem, ALIGN_16);
Adapter->SelfTestPhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16);
pMem = (PUCHAR)Adapter->SelfTest + sizeof(SELF_TEST_STRUC);
MemPhys = Adapter->SelfTestPhys + sizeof(SELF_TEST_STRUC);
Adapter->NonTxCmdBlock = (PNON_TRANSMIT_CB)MP_ALIGNMEM(pMem, ALIGN_16);
Adapter->NonTxCmdBlockPhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16);
pMem = (PUCHAR)Adapter->NonTxCmdBlock + sizeof(NON_TRANSMIT_CB);
MemPhys = Adapter->NonTxCmdBlockPhys + sizeof(NON_TRANSMIT_CB);
Adapter->DumpSpace = (PDUMP_AREA_STRUC)MP_ALIGNMEM(pMem, ALIGN_16);
Adapter->DumpSpacePhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16);
pMem = (PUCHAR)Adapter->DumpSpace + sizeof(DUMP_AREA_STRUC);
MemPhys = Adapter->DumpSpacePhys + sizeof(DUMP_AREA_STRUC);
Adapter->StatsCounters = (PERR_COUNT_STRUC)MP_ALIGNMEM(pMem, ALIGN_16);
Adapter->StatsCounterPhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16);
// HW_END
//
// Recv
//
NdisInitializeNPagedLookasideList(
&Adapter->RecvLookaside,
NULL,
NULL,
0,
sizeof(MP_RFD),
NIC_TAG,
0);
MP_SET_FLAG(Adapter, fMP_ADAPTER_RECV_LOOKASIDE);
// set the max number of RFDs
// disable the RFD grow/shrink scheme if user specifies a NumRfd value
// larger than NIC_MAX_GROW_RFDS
Adapter->MaxNumRfd = max(Adapter->NumRfd, NIC_MAX_GROW_RFDS);
DBGPRINT(MP_INFO, ("NumRfd = %d\n", Adapter->NumRfd));
DBGPRINT(MP_INFO, ("MaxNumRfd = %d\n", Adapter->MaxNumRfd));
Adapter->HwRfdSize = sizeof(RFD_STRUC);
// alloc the recv packet pool
NdisAllocatePacketPoolEx(
&Status,
&Adapter->RecvPacketPool,
Adapter->NumRfd,
Adapter->MaxNumRfd,
sizeof(PVOID) * 4);
if (Status != NDIS_STATUS_SUCCESS)
{
ErrorValue = ERRLOG_OUT_OF_PACKET_POOL;
break;
}
// alloc the buffer pool
NdisAllocateBufferPool(
&Status,
&Adapter->RecvBufferPool,
Adapter->MaxNumRfd);
if (Status != NDIS_STATUS_SUCCESS)
{
ErrorValue = ERRLOG_OUT_OF_BUFFER_POOL;
break;
}
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
if (Status != NDIS_STATUS_SUCCESS)
{
NdisWriteErrorLogEntry(
Adapter->AdapterHandle,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
1,
ErrorValue);
}
#if OFFLOAD
// Allocate the shared memory for the offloading packet
// this miniport use this shared memory when OFFLAOD is on
for (i = 0; i < LARGE_SEND_MEM_SIZE_OPTION; i++)
{
NdisMAllocateSharedMemory(
Adapter->AdapterHandle,
LargeSendSharedMemArray[i],
FALSE,
(PVOID *)&(Adapter->OffloadSharedMem.StartVa),
&(Adapter->OffloadSharedMem.PhyAddr));
if (Adapter->OffloadSharedMem.StartVa)
{
Adapter->OffloadSharedMemSize = LargeSendSharedMemArray[i];
OffloadSharedMemSuccess = TRUE;
Adapter->OffloadEnable = TRUE;
break;
}
}
if (OffloadSharedMemSuccess == FALSE)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
DBGPRINT(MP_ERROR, ("Failed to allocate offload used memory\n"));
Adapter->OffloadEnable = FALSE;
}
#endif
DBGPRINT_S(Status, ("<-- NICAllocMemory, Status=%x\n", Status));
return Status;
}
VOID NICInitSend(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Initialize send data structures
Arguments:
Adapter Pointer to our adapter
Return Value:
None
--*/
{
PMP_TCB pMpTcb;
PHW_TCB pHwTcb;
ULONG HwTcbPhys;
LONG TcbCount;
PTBD_STRUC pHwTbd;
ULONG HwTbdPhys;
DBGPRINT(MP_TRACE, ("--> NICInitSend\n"));
Adapter->TransmitIdle = TRUE;
Adapter->ResumeWait = TRUE;
// Setup the initial pointers to the SW and HW TCB data space
pMpTcb = (PMP_TCB) Adapter->MpTcbMem;
pHwTcb = (PHW_TCB) Adapter->HwSendMemAllocVa;
HwTcbPhys = NdisGetPhysicalAddressLow(Adapter->HwSendMemAllocPa);
// Setup the initial pointers to the TBD data space.
// TBDs are located immediately following the TCBs
pHwTbd = (PTBD_STRUC) (Adapter->HwSendMemAllocVa +
(sizeof(TXCB_STRUC) * Adapter->NumTcb));
HwTbdPhys = HwTcbPhys + (sizeof(TXCB_STRUC) * Adapter->NumTcb);
// Go through and set up each TCB
for (TcbCount = 0; TcbCount < Adapter->NumTcb; TcbCount++)
{
pMpTcb->HwTcb = pHwTcb; // save ptr to HW TCB
pMpTcb->HwTcbPhys = HwTcbPhys; // save HW TCB physical address
pMpTcb->HwTbd = pHwTbd; // save ptr to TBD array
pMpTcb->HwTbdPhys = HwTbdPhys; // save TBD array physical address
if (TcbCount)
pMpTcb->PrevHwTcb = pHwTcb - 1;
else
pMpTcb->PrevHwTcb = (PHW_TCB)((PUCHAR)Adapter->HwSendMemAllocVa +
((Adapter->NumTcb - 1) * sizeof(HW_TCB)));
pHwTcb->TxCbHeader.CbStatus = 0; // clear the status
pHwTcb->TxCbHeader.CbCommand = CB_EL_BIT | CB_TX_SF_BIT | CB_TRANSMIT;
// Set the link pointer in HW TCB to the next TCB in the chain.
// If this is the last TCB in the chain, then set it to the first TCB.
if (TcbCount < Adapter->NumTcb - 1)
{
pMpTcb->Next = pMpTcb + 1;
pHwTcb->TxCbHeader.CbLinkPointer = HwTcbPhys + sizeof(HW_TCB);
}
else
{
pMpTcb->Next = (PMP_TCB) Adapter->MpTcbMem;
pHwTcb->TxCbHeader.CbLinkPointer =
NdisGetPhysicalAddressLow(Adapter->HwSendMemAllocPa);
}
pHwTcb->TxCbThreshold = (UCHAR) Adapter->AiThreshold;
pHwTcb->TxCbTbdPointer = HwTbdPhys;
pMpTcb++;
pHwTcb++;
HwTcbPhys += sizeof(TXCB_STRUC);
pHwTbd = (PTBD_STRUC)((PUCHAR)pHwTbd + sizeof(TBD_STRUC) * NIC_MAX_PHYS_BUF_COUNT);
HwTbdPhys += sizeof(TBD_STRUC) * NIC_MAX_PHYS_BUF_COUNT;
}
// set the TCB head/tail indexes
// head is the olded one to free, tail is the next one to use
Adapter->CurrSendHead = (PMP_TCB) Adapter->MpTcbMem;
Adapter->CurrSendTail = (PMP_TCB) Adapter->MpTcbMem;
// set the map register head/tail indexes if used
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_MAP_REGISTER))
{
Adapter->CurrMapRegHead = 0;
Adapter->CurrMapRegTail = 0;
}
DBGPRINT(MP_TRACE, ("<-- NICInitSend, Status=%x\n"));
}
NDIS_STATUS NICInitRecv(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Initialize receive data structures
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_RESOURCES
--*/
{
NDIS_STATUS Status = NDIS_STATUS_RESOURCES;
PMP_RFD pMpRfd;
LONG RfdCount;
ULONG ErrorValue = 0;
DBGPRINT(MP_TRACE, ("--> NICInitRecv\n"));
// Setup each RFD
for (RfdCount = 0; RfdCount < Adapter->NumRfd; RfdCount++)
{
pMpRfd = NdisAllocateFromNPagedLookasideList(&Adapter->RecvLookaside);
if (!pMpRfd)
{
ErrorValue = ERRLOG_OUT_OF_LOOKASIDE_MEMORY;
continue;
}
// Allocate the shared memory for this RFD.
NdisMAllocateSharedMemory(
Adapter->AdapterHandle,
Adapter->HwRfdSize,
FALSE,
&pMpRfd->HwRfd,
&pMpRfd->HwRfdPa);
if (!pMpRfd->HwRfd)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pMpRfd);
continue;
}
ErrorValue = NICAllocRfd(Adapter, pMpRfd);
if (ErrorValue)
{
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pMpRfd);
continue;
}
// Add this RFD to the RecvList
Adapter->CurrNumRfd++;
NICReturnRFD(Adapter, pMpRfd);
}
if (Adapter->CurrNumRfd > NIC_MIN_RFDS)
{
Status = NDIS_STATUS_SUCCESS;
}
if (Status != NDIS_STATUS_SUCCESS)
{
NdisWriteErrorLogEntry(
Adapter->AdapterHandle,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
1,
ErrorValue);
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pMpRfd);
}
DBGPRINT_S(Status, ("<-- NICInitRecv, Status=%x\n", Status));
return Status;
}
ULONG NICAllocRfd(
IN PMP_ADAPTER Adapter,
IN PMP_RFD pMpRfd)
/*++
Routine Description:
Allocate NDIS_PACKET and NDIS_BUFFER associated with a RFD
Arguments:
Adapter Pointer to our adapter
pMpRfd pointer to a RFD
Return Value:
ERRLOG_OUT_OF_NDIS_PACKET
ERRLOG_OUT_OF_NDIS_BUFFER
--*/
{
NDIS_STATUS Status;
PHW_RFD pHwRfd;
ULONG HwRfdPhys;
ULONG ErrorValue = 0;
do
{
pHwRfd = pMpRfd->HwRfd;
pMpRfd->HwRfdPhys = NdisGetPhysicalAddressLow(pMpRfd->HwRfdPa);
pMpRfd->Flags = 0;
pMpRfd->NdisPacket = NULL;
pMpRfd->NdisBuffer = NULL;
NdisAllocatePacket(
&Status,
&pMpRfd->NdisPacket,
Adapter->RecvPacketPool);
if (Status != NDIS_STATUS_SUCCESS)
{
ASSERT(pMpRfd->NdisPacket == NULL);
ErrorValue = ERRLOG_OUT_OF_NDIS_PACKET;
break;
}
// point our buffer for receives at this Rfd
NdisAllocateBuffer(
&Status,
&pMpRfd->NdisBuffer,
Adapter->RecvBufferPool,
(PVOID)&pHwRfd->RfdBuffer.RxMacHeader,
NIC_MAX_PACKET_SIZE);
if (Status != NDIS_STATUS_SUCCESS)
{
ASSERT(pMpRfd->NdisBuffer == NULL);
ErrorValue = ERRLOG_OUT_OF_NDIS_BUFFER;
break;
}
// Init each RFD header
pHwRfd->RfdRbdPointer = DRIVER_NULL;
pHwRfd->RfdSize = NIC_MAX_PACKET_SIZE;
NDIS_SET_PACKET_HEADER_SIZE(pMpRfd->NdisPacket, NIC_HEADER_SIZE);
NdisChainBufferAtFront(pMpRfd->NdisPacket, pMpRfd->NdisBuffer);
// Save ptr to MP_RFD in the packet, used in MPReturnPackets
MP_SET_PACKET_RFD(pMpRfd->NdisPacket, pMpRfd);
return ErrorValue;
} while (FALSE);
if (ErrorValue)
{
if (pMpRfd->NdisPacket)
{
NdisFreePacket(pMpRfd->NdisPacket);
}
if (pMpRfd->HwRfd)
{
NdisMFreeSharedMemory(
Adapter->AdapterHandle,
Adapter->HwRfdSize,
FALSE,
pMpRfd->HwRfd,
pMpRfd->HwRfdPa);
}
}
return ErrorValue;
}
VOID NICFreeRfd(
IN PMP_ADAPTER Adapter,
IN PMP_RFD pMpRfd)
/*++
Routine Description:
Free a RFD and assocaited NDIS_PACKET and NDIS_BUFFER
Arguments:
Adapter Pointer to our adapter
pMpRfd Pointer to a RFD
Return Value:
None
--*/
{
ASSERT(pMpRfd->NdisBuffer);
ASSERT(pMpRfd->NdisPacket);
ASSERT(pMpRfd->HwRfd);
NdisFreeBuffer(pMpRfd->NdisBuffer);
NdisFreePacket(pMpRfd->NdisPacket);
pMpRfd->NdisBuffer = NULL;
pMpRfd->NdisPacket = NULL;
NdisMFreeSharedMemory(
Adapter->AdapterHandle,
Adapter->HwRfdSize,
FALSE,
pMpRfd->HwRfd,
pMpRfd->HwRfdPa);
pMpRfd->HwRfd = NULL;
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pMpRfd);
}
NDIS_STATUS NICSelfTest(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Perform a NIC self-test
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_DEVICE_FAILED
--*/
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
ULONG SelfTestCommandCode;
DBGPRINT(MP_TRACE, ("--> NICSelfTest\n"));
DBGPRINT(MP_INFO, ("SelfTest=%x, SelfTestPhys=%x\n",
Adapter->SelfTest, Adapter->SelfTestPhys));
// Issue a software reset to the adapter
HwSoftwareReset(Adapter);
// Execute The PORT Self Test Command On The 82558.
ASSERT(Adapter->SelfTestPhys != 0);
SelfTestCommandCode = Adapter->SelfTestPhys;
// Setup SELF TEST Command Code in D3 - D0
SelfTestCommandCode |= PORT_SELFTEST;
// Initialize the self-test signature and results DWORDS
Adapter->SelfTest->StSignature = 0;
Adapter->SelfTest->StResults = 0xffffffff;
// Do the port command
Adapter->CSRAddress->Port = SelfTestCommandCode;
MP_STALL_EXECUTION(NIC_DELAY_POST_SELF_TEST_MS);
// if The First Self Test DWORD Still Zero, We've timed out. If the second
// DWORD is not zero then we have an error.
if ((Adapter->SelfTest->StSignature == 0) || (Adapter->SelfTest->StResults != 0))
{
DBGPRINT(MP_ERROR, ("StSignature=%x, StResults=%x\n",
Adapter->SelfTest->StSignature, Adapter->SelfTest->StResults));
NdisWriteErrorLogEntry(
Adapter->AdapterHandle,
NDIS_ERROR_CODE_HARDWARE_FAILURE,
1,
ERRLOG_SELFTEST_FAILED);
Status = NDIS_STATUS_DEVICE_FAILED;
}
DBGPRINT_S(Status, ("<-- NICSelfTest, Status=%x\n", Status));
return Status;
}
NDIS_STATUS NICInitializeAdapter(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Initialize the adapter and set up everything
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_HARD_ERRORS
--*/
{
NDIS_STATUS Status;
USHORT EepromFlags;
DBGPRINT(MP_TRACE, ("--> NICInitializeAdapter\n"));
do
{
// set up our link indication variable
// it doesn't matter what this is right now because it will be
// set correctly if link fails
Adapter->MediaState = NdisMediaStateConnected;
Adapter->CurrentPowerState = NdisDeviceStateD0;
Adapter->NextPowerState = NdisDeviceStateD0;
// Issue a software reset to the D100
HwSoftwareReset(Adapter);
// Load the CU BASE (set to 0, because we use linear mode)
Adapter->CSRAddress->ScbGeneralPointer = 0;
Status = D100IssueScbCommand(Adapter, SCB_CUC_LOAD_BASE, FALSE);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
// Wait for the SCB command word to clear before we set the general pointer
if (!WaitScb(Adapter))
{
Status = NDIS_STATUS_HARD_ERRORS;
break;
}
// Load the RU BASE (set to 0, because we use linear mode)
Adapter->CSRAddress->ScbGeneralPointer = 0;
Status = D100IssueScbCommand(Adapter, SCB_RUC_LOAD_BASE, FALSE);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
// Configure the adapter
Status = HwConfigure(Adapter);
if (Status != NDIS_STATUS_SUCCESS) break;
Status = HwSetupIAAddress(Adapter);
if (Status != NDIS_STATUS_SUCCESS) break;
// Clear the internal counters
HwClearAllCounters(Adapter);
} while (FALSE);
if (Status != NDIS_STATUS_SUCCESS)
{
NdisWriteErrorLogEntry(
Adapter->AdapterHandle,
NDIS_ERROR_CODE_HARDWARE_FAILURE,
1,
ERRLOG_INITIALIZE_ADAPTER);
}
DBGPRINT_S(Status, ("<-- NICInitializeAdapter, Status=%x\n", Status));
return Status;
}
VOID HwSoftwareReset(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Issue a software reset to the hardware
Arguments:
Adapter Pointer to our adapter
Return Value:
None
--*/
{
DBGPRINT(MP_TRACE, ("--> HwSoftwareReset\n"));
// Issue a PORT command with a data word of 0
Adapter->CSRAddress->Port = PORT_SOFTWARE_RESET;
// wait after the port reset command
NdisStallExecution(NIC_DELAY_POST_RESET);
// Mask off our interrupt line -- its unmasked after reset
NICDisableInterrupt(Adapter);
DBGPRINT(MP_TRACE, ("<-- HwSoftwareReset\n"));
}
NDIS_STATUS HwConfigure(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Configure the hardware
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_HARD_ERRORS
--*/
{
NDIS_STATUS Status;
PCB_HEADER_STRUC NonTxCmdBlockHdr = (PCB_HEADER_STRUC)Adapter->NonTxCmdBlock;
UINT i;
DBGPRINT(MP_TRACE, ("--> HwConfigure\n"));
// Init the packet filter to nothing.
Adapter->PacketFilter = 0;
//
// Store the current setting for BROADCAST/PROMISCUOS modes
Adapter->OldParameterField = CB_557_CFIG_DEFAULT_PARM15;
// Setup the non-transmit command block header for the configure command.
NonTxCmdBlockHdr->CbStatus = 0;
NonTxCmdBlockHdr->CbCommand = CB_CONFIGURE;
NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL;
// Fill in the configure command data.
// First fill in the static (end user can't change) config bytes
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[0] = CB_557_CFIG_DEFAULT_PARM0;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[2] = CB_557_CFIG_DEFAULT_PARM2;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] = CB_557_CFIG_DEFAULT_PARM3;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[6] = CB_557_CFIG_DEFAULT_PARM6;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[9] = CB_557_CFIG_DEFAULT_PARM9;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[10] = CB_557_CFIG_DEFAULT_PARM10;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[11] = CB_557_CFIG_DEFAULT_PARM11;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[12] = CB_557_CFIG_DEFAULT_PARM12;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[13] = CB_557_CFIG_DEFAULT_PARM13;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[14] = CB_557_CFIG_DEFAULT_PARM14;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[16] = CB_557_CFIG_DEFAULT_PARM16;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[17] = CB_557_CFIG_DEFAULT_PARM17;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[18] = CB_557_CFIG_DEFAULT_PARM18;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[20] = CB_557_CFIG_DEFAULT_PARM20;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] = CB_557_CFIG_DEFAULT_PARM21;
// Now fill in the rest of the configuration bytes (the bytes that contain
// user configurable parameters).
// Set the Tx and Rx Fifo limits
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[1] =
(UCHAR) ((Adapter->AiTxFifo << 4) | Adapter->AiRxFifo);
if (Adapter->MWIEnable)
{
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] |= CB_CFIG_B3_MWI_ENABLE;
}
// Set the Tx and Rx DMA maximum byte count fields.
if ((Adapter->AiRxDmaCount) || (Adapter->AiTxDmaCount))
{
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] =
Adapter->AiRxDmaCount;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] =
(UCHAR) (Adapter->AiTxDmaCount | CB_CFIG_DMBC_EN);
}
else
{
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] =
CB_557_CFIG_DEFAULT_PARM4;
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] =
CB_557_CFIG_DEFAULT_PARM5;
}
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[7] =
(UCHAR) ((CB_557_CFIG_DEFAULT_PARM7 & (~CB_CFIG_URUN_RETRY)) |
(Adapter->AiUnderrunRetry << 1)
);
// Setup for MII or 503 operation. The CRS+CDT bit should only be set
// when operating in 503 mode.
if (Adapter->PhyAddress == 32)
{
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] =
(CB_557_CFIG_DEFAULT_PARM8 & (~CB_CFIG_503_MII));
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] =
(CB_557_CFIG_DEFAULT_PARM15 | CB_CFIG_CRS_OR_CDT);
}
else
{
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] =
(CB_557_CFIG_DEFAULT_PARM8 | CB_CFIG_503_MII);
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] =
((CB_557_CFIG_DEFAULT_PARM15 & (~CB_CFIG_CRS_OR_CDT)) | CB_CFIG_BROADCAST_DIS);
}
// Setup Full duplex stuff
// If forced to half duplex
if (Adapter->AiForceDpx == 1)
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
(CB_557_CFIG_DEFAULT_PARM19 &
(~(CB_CFIG_FORCE_FDX| CB_CFIG_FDX_ENABLE)));
// If forced to full duplex
else if (Adapter->AiForceDpx == 2)
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
(CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX);
// If auto-duplex
else
{
// We must force full duplex on if we are using PHY 0, and we are
// supposed to run in FDX mode. We do this because the D100 has only
// one FDX# input pin, and that pin will be connected to PHY 1.
if ((Adapter->PhyAddress == 0) && (Adapter->usDuplexMode == 2))
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
(CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX);
else
Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
CB_557_CFIG_DEFAULT_PARM19;
}
// display the config info to the debugger
DBGPRINT(MP_INFO, (" Issuing Configure command\n"));
DBGPRINT(MP_INFO, (" Config Block at virt addr "PTR_FORMAT", phys address %x\n",
&NonTxCmdBlockHdr->CbStatus, Adapter->NonTxCmdBlockPhys));
for (i=0; i < CB_CFIG_BYTE_COUNT; i++)
DBGPRINT(MP_INFO, (" Config byte %x = %.2x\n",
i, Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[i]));
// Wait for the SCB command word to clear before we set the general pointer
if (!WaitScb(Adapter))
{
Status = NDIS_STATUS_HARD_ERRORS;
}
else
{
ASSERT(Adapter->CSRAddress->ScbCommandLow == 0)
Adapter->CSRAddress->ScbGeneralPointer = Adapter->NonTxCmdBlockPhys;
// Submit the configure command to the chip, and wait for it to complete.
Status = D100SubmitCommandBlockAndWait(Adapter);
}
DBGPRINT_S(Status, ("<-- HwConfigure, Status=%x\n", Status));
return Status;
}
NDIS_STATUS HwSetupIAAddress(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
Set up the individual MAC address
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_SUCCESS_HARD_ERRORS
--*/
{
NDIS_STATUS Status;
UINT i;
PCB_HEADER_STRUC NonTxCmdBlockHdr = (PCB_HEADER_STRUC)Adapter->NonTxCmdBlock;
DBGPRINT(MP_TRACE, ("--> HwSetupIAAddress\n"));
// Individual Address Setup
NonTxCmdBlockHdr->CbStatus = 0;
NonTxCmdBlockHdr->CbCommand = CB_IA_ADDRESS;
NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL;
// Copy in the station's individual address
for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++)
Adapter->NonTxCmdBlock->NonTxCb.Setup.IaAddress[i] = Adapter->CurrentAddress[i];
// Update the command list pointer. We don't need to do a WaitSCB here
// because this command is either issued immediately after a reset, or
// after another command that runs in polled mode. This guarantees that
// the low byte of the SCB command word will be clear. The only commands
// that don't run in polled mode are transmit and RU-start commands.
ASSERT(Adapter->CSRAddress->ScbCommandLow == 0)
Adapter->CSRAddress->ScbGeneralPointer = Adapter->NonTxCmdBlockPhys;
// Submit the IA configure command to the chip, and wait for it to complete.
Status = D100SubmitCommandBlockAndWait(Adapter);
DBGPRINT_S(Status, ("<-- HwSetupIAAddress, Status=%x\n", Status));
return Status;
}
NDIS_STATUS HwClearAllCounters(
IN PMP_ADAPTER Adapter)
/*++
Routine Description:
This routine will clear the hardware error statistic counters
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_HARD_ERRORS
--*/
{
NDIS_STATUS Status;
BOOLEAN bResult;
DBGPRINT(MP_TRACE, ("--> HwClearAllCounters\n"));
do
{
// Load the dump counters pointer. Since this command is generated only
// after the IA setup has complete, we don't need to wait for the SCB
// command word to clear
ASSERT(Adapter->CSRAddress->ScbCommandLow == 0)
Adapter->CSRAddress->ScbGeneralPointer = Adapter->StatsCounterPhys;
// Issue the load dump counters address command
Status = D100IssueScbCommand(Adapter, SCB_CUC_DUMP_ADDR, FALSE);
if (Status != NDIS_STATUS_SUCCESS) break;
// Now dump and reset all of the statistics
Status = D100IssueScbCommand(Adapter, SCB_CUC_DUMP_RST_STAT, TRUE);
if (Status != NDIS_STATUS_SUCCESS) break;
// Now wait for the dump/reset to complete, timeout value 2 secs
MP_STALL_AND_WAIT(Adapter->StatsCounters->CommandComplete == 0xA007, 2000, bResult);
if (!bResult)
{
MP_SET_HARDWARE_ERROR(Adapter);
Status = NDIS_STATUS_HARD_ERRORS;
break;
}
// init packet counts
Adapter->GoodTransmits = 0;
Adapter->GoodReceives = 0;
// init transmit error counts
Adapter->TxAbortExcessCollisions = 0;
Adapter->TxLateCollisions = 0;
Adapter->TxDmaUnderrun = 0;
Adapter->TxLostCRS = 0;
Adapter->TxOKButDeferred = 0;
Adapter->OneRetry = 0;
Adapter->MoreThanOneRetry = 0;
Adapter->TotalRetries = 0;
// init receive error counts
Adapter->RcvCrcErrors = 0;
Adapter->RcvAlignmentErrors = 0;
Adapter->RcvResourceErrors = 0;
Adapter->RcvDmaOverrunErrors = 0;
Adapter->RcvCdtFrames = 0;
Adapter->RcvRuntErrors = 0;
} while (FALSE);
DBGPRINT_S(Status, ("<-- HwClearAllCounters, Status=%x\n", Status));
return Status;
}