Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322/* * PROJECT: ReactOS DC21x4 Driver * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Miniport initialization helper routines * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com> */
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* GLOBALS ********************************************************************/
/* * The driver must align the buffers on a 4 byte boundary to meet the hardware requirement. * We stick with cache alignment to get better performance. */C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_RECEIVE_BUFFER_ALIGNMENT) == 0);C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_DESCRIPTOR_ALIGNMENT) == 0);C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_SETUP_FRAME_ALIGNMENT) == 0);
/* Errata: The end of receive buffer must not fall on a cache boundary */#define DC_RECEIVE_BUFFER_SIZE (DC_RECEIVE_BLOCK_SIZE - 4)C_ASSERT((DC_RECEIVE_BUFFER_SIZE % 32) != 0);
#define DC_MEM_BLOCK_SIZE_RCB \ (DC_RECEIVE_BLOCK_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
#define DC_MEM_BLOCK_SIZE_RBD \ (sizeof(DC_RBD) * DC_RECEIVE_BUFFERS_DEFAULT + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
#define DC_MEM_BLOCK_SIZE_TBD_AUX \ (sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS + SYSTEM_CACHE_ALIGNMENT_SIZE - 1 + \ DC_SETUP_FRAME_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1 + \ DC_LOOPBACK_FRAME_SIZE * DC_LOOPBACK_FRAMES + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
#define DC_MEM_BLOCK_SIZE_TX_BUFFER \ (DC_TRANSMIT_BLOCK_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
/* FUNCTIONS ******************************************************************/
staticCODE_SEG("PAGE")VOIDDcConfigQueryInteger( _In_ NDIS_HANDLE ConfigurationHandle, _In_ PCWSTR EntryName, _Out_ PULONG EntryContext, _In_ ULONG DefaultValue, _In_ ULONG Minimum, _In_ ULONG Maximum){ NDIS_STATUS Status; UNICODE_STRING Keyword; PNDIS_CONFIGURATION_PARAMETER ConfigurationParameter;
PAGED_CODE();
NdisInitUnicodeString(&Keyword, EntryName); NdisReadConfiguration(&Status, &ConfigurationParameter, ConfigurationHandle, &Keyword, NdisParameterInteger); if (Status != NDIS_STATUS_SUCCESS) { TRACE("'%S' request failed, default value %u\n", EntryName, DefaultValue);
*EntryContext = DefaultValue; return; }
if (ConfigurationParameter->ParameterData.IntegerData >= Minimum && ConfigurationParameter->ParameterData.IntegerData <= Maximum) { *EntryContext = ConfigurationParameter->ParameterData.IntegerData; } else { WARN("'%S' value out of range\n", EntryName);
*EntryContext = DefaultValue; }
TRACE("Set '%S' to %u\n", EntryName, *EntryContext);}
staticCODE_SEG("PAGE")NDIS_STATUSDcReadConfiguration( _In_ PDC21X4_ADAPTER Adapter){ NDIS_STATUS Status; NDIS_HANDLE ConfigurationHandle; PUCHAR NetworkAddress; UINT Length; ULONG GenericUlong;
PAGED_CODE();
NdisOpenConfiguration(&Status, &ConfigurationHandle, Adapter->WrapperConfigurationHandle); if (Status != NDIS_STATUS_SUCCESS) return Status;
DcConfigQueryInteger(ConfigurationHandle, L"SpeedDuplex", &GenericUlong, MEDIA_AUTO, MEDIA_10T, MEDIA_HMR); Adapter->DefaultMedia = GenericUlong;
NdisReadNetworkAddress(&Status, (PVOID*)&NetworkAddress, &Length, ConfigurationHandle); if ((Status == NDIS_STATUS_SUCCESS) && (Length == ETH_LENGTH_OF_ADDRESS)) { if (ETH_IS_MULTICAST(NetworkAddress) || ETH_IS_EMPTY(NetworkAddress) || ETH_IS_BROADCAST(NetworkAddress) || !ETH_IS_LOCALLY_ADMINISTERED(NetworkAddress)) { ERR("Invalid software MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", NetworkAddress[0], NetworkAddress[1], NetworkAddress[2], NetworkAddress[3], NetworkAddress[4], NetworkAddress[5]); } else { INFO("Using software MAC address\n");
/* Override the MAC address */ NdisMoveMemory(Adapter->CurrentMacAddress, NetworkAddress, ETH_LENGTH_OF_ADDRESS); } }
NdisCloseConfiguration(ConfigurationHandle);
return NDIS_STATUS_SUCCESS;}
staticCODE_SEG("PAGE")VOIDDcFreeRcb( _In_ PDC21X4_ADAPTER Adapter, _In_ __drv_freesMem(Mem) PDC_RCB Rcb){ PAGED_CODE();
if (Rcb->VirtualAddressOriginal) { NdisMFreeSharedMemory(Adapter->AdapterHandle, DC_MEM_BLOCK_SIZE_RCB, TRUE, /* Cached */ Rcb->VirtualAddressOriginal, Rcb->PhysicalAddressOriginal); }
if (Rcb->NdisBuffer) NdisFreeBuffer(Rcb->NdisBuffer); if (Rcb->Packet) NdisFreePacket(Rcb->Packet);
NdisFreeMemory(Rcb, sizeof(*Rcb), 0);}
staticCODE_SEG("PAGE")PDC_RCBDcAllocateRcb( _In_ PDC21X4_ADAPTER Adapter){ NDIS_STATUS Status; PDC_RCB Rcb; PVOID VirtualAddress; NDIS_PHYSICAL_ADDRESS PhysicalAddress;
PAGED_CODE();
Status = NdisAllocateMemoryWithTag((PVOID*)&Rcb, sizeof(*Rcb), DC21X4_TAG); if (Status != NDIS_STATUS_SUCCESS) return NULL; NdisZeroMemory(Rcb, sizeof(*Rcb));
NdisMAllocateSharedMemory(Adapter->AdapterHandle, DC_MEM_BLOCK_SIZE_RCB, TRUE, /* Cached */ &VirtualAddress, &PhysicalAddress); if (!VirtualAddress) goto Failure;
/* 32-bit DMA */ ASSERT(PhysicalAddress.HighPart == 0);
Rcb->VirtualAddress = ALIGN_UP_POINTER_BY(VirtualAddress, SYSTEM_CACHE_ALIGNMENT_SIZE); Rcb->PhysicalAddress = ALIGN_UP_BY(PhysicalAddress.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE);
ASSERT((Rcb->PhysicalAddress % DC_RECEIVE_BUFFER_ALIGNMENT) == 0);
Rcb->VirtualAddressOriginal = VirtualAddress; Rcb->PhysicalAddressOriginal.QuadPart = PhysicalAddress.QuadPart;
NdisAllocatePacket(&Status, &Rcb->Packet, Adapter->PacketPool); if (Status != NDIS_STATUS_SUCCESS) goto Failure;
*DC_RCB_FROM_PACKET(Rcb->Packet) = Rcb;
NdisAllocateBuffer(&Status, &Rcb->NdisBuffer, Adapter->BufferPool, Rcb->VirtualAddress, DC_RECEIVE_BLOCK_SIZE); if (Status != NDIS_STATUS_SUCCESS) goto Failure;
NDIS_SET_PACKET_HEADER_SIZE(Rcb->Packet, DC_ETHERNET_HEADER_SIZE); NdisChainBufferAtFront(Rcb->Packet, Rcb->NdisBuffer);
PushEntryList(&Adapter->AllocRcbList, &Rcb->AllocListEntry);
return Rcb;
Failure: DcFreeRcb(Adapter, Rcb);
return NULL;}
staticCODE_SEG("PAGE")NDIS_STATUSDcAllocateReceiveBuffers( _In_ PDC21X4_ADAPTER Adapter){ ULONG i; NDIS_STATUS Status; PDC_RCB Rcb;
PAGED_CODE();
NdisAllocatePacketPool(&Status, &Adapter->PacketPool, DC_RECEIVE_BUFFERS_DEFAULT + DC_RECEIVE_BUFFERS_EXTRA, PROTOCOL_RESERVED_SIZE_IN_PACKET); if (Status != NDIS_STATUS_SUCCESS) return Status;
NdisAllocateBufferPool(&Status, &Adapter->BufferPool, DC_RECEIVE_BUFFERS_DEFAULT + DC_RECEIVE_BUFFERS_EXTRA); if (Status != NDIS_STATUS_SUCCESS) return Status;
/* Allocate RCBs */ for (i = 0; i < DC_RECEIVE_BUFFERS_DEFAULT; ++i) { Rcb = DcAllocateRcb(Adapter); if (!Rcb) { WARN("RCB allocation failed, total buffers %u\n", Adapter->RcbCount); break; }
PushEntryList(&Adapter->UsedRcbList, &Rcb->ListEntry);
++Adapter->RcbCount; }
if (Adapter->RcbCount < DC_RECEIVE_BUFFERS_MIN) return NDIS_STATUS_RESOURCES;
Adapter->RcbFree = Adapter->RcbCount;
/* Fix up the ring size */ Adapter->TailRbd = Adapter->HeadRbd + Adapter->RcbCount - 1;
/* Allocate extra RCBs for receive indication */ for (i = 0; i < DC_RECEIVE_BUFFERS_EXTRA; ++i) { Rcb = DcAllocateRcb(Adapter); if (!Rcb) { WARN("Extra RCB allocation failed\n"); break; }
PushEntryList(&Adapter->FreeRcbList, &Rcb->ListEntry); }
Status = NdisAllocateMemoryWithTag((PVOID*)&Adapter->RcbArray, sizeof(PVOID) * Adapter->RcbCount, DC21X4_TAG); if (Status != NDIS_STATUS_SUCCESS) return Status;
return NDIS_STATUS_SUCCESS;}
staticCODE_SEG("PAGE")NDIS_STATUSDcAllocateReceiveDescriptors( _In_ PDC21X4_ADAPTER Adapter){ PDC_RBD Rbd;
PAGED_CODE();
NdisMAllocateSharedMemory(Adapter->AdapterHandle, DC_MEM_BLOCK_SIZE_RBD, FALSE, /* Non-cached */ &Adapter->RbdOriginal, &Adapter->RbdPhysOriginal); if (!Adapter->RbdOriginal) return NDIS_STATUS_RESOURCES;
/* 32-bit DMA */ ASSERT(Adapter->RbdPhysOriginal.HighPart == 0);
Adapter->RbdPhys = ALIGN_UP_BY(Adapter->RbdPhysOriginal.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE);
ASSERT((Adapter->RbdPhys % DC_DESCRIPTOR_ALIGNMENT) == 0);
Rbd = ALIGN_UP_POINTER_BY(Adapter->RbdOriginal, SYSTEM_CACHE_ALIGNMENT_SIZE);
Adapter->HeadRbd = Rbd;
return NDIS_STATUS_SUCCESS;}
staticCODE_SEG("PAGE")NDIS_STATUSDcAllocateTransmitBlocks( _In_ PDC21X4_ADAPTER Adapter){ PDC_TCB Tcb; NDIS_STATUS Status;
PAGED_CODE();
Status = NdisAllocateMemoryWithTag((PVOID*)&Tcb, DC_TRANSMIT_BLOCKS * sizeof(*Tcb), DC21X4_TAG); if (Status != NDIS_STATUS_SUCCESS) return Status;
NdisZeroMemory(Tcb, DC_TRANSMIT_BLOCKS * sizeof(*Tcb));
Adapter->HeadTcb = Tcb; Adapter->TailTcb = Tcb + (DC_TRANSMIT_BLOCKS - 1);
return NDIS_STATUS_SUCCESS;}
staticCODE_SEG("PAGE")NDIS_STATUSDcAllocateTransmitDescriptorsAndBuffers( _In_ PDC21X4_ADAPTER Adapter){ ULONG_PTR BufferVa, BufferPa; NDIS_STATUS Status; ULONG i;
PAGED_CODE();
NdisMAllocateSharedMemory(Adapter->AdapterHandle, DC_MEM_BLOCK_SIZE_TBD_AUX, FALSE, /* Non-cached */ &Adapter->TbdOriginal, &Adapter->TbdPhysOriginal); if (!Adapter->TbdOriginal) return NDIS_STATUS_RESOURCES;
/* 32-bit DMA */ ASSERT(Adapter->TbdPhysOriginal.HighPart == 0);
BufferVa = (ULONG_PTR)Adapter->TbdOriginal; BufferPa = Adapter->TbdPhysOriginal.LowPart;
BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE); BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE);
ASSERT((BufferPa % DC_DESCRIPTOR_ALIGNMENT) == 0);
Adapter->TbdPhys = (ULONG)BufferPa; Adapter->HeadTbd = (PDC_TBD)BufferVa; Adapter->TailTbd = (PDC_TBD)BufferVa + DC_TRANSMIT_DESCRIPTORS - 1;
BufferVa += sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS; BufferPa += sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS;
BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE); BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE);
ASSERT((BufferPa % DC_SETUP_FRAME_ALIGNMENT) == 0);
Adapter->SetupFrame = (PVOID)BufferVa; Adapter->SetupFramePhys = BufferPa;
BufferVa += DC_SETUP_FRAME_SIZE; BufferPa += DC_SETUP_FRAME_SIZE;
BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE); BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE);
for (i = 0; i < DC_LOOPBACK_FRAMES; ++i) { Adapter->LoopbackFrame[i] = (PVOID)BufferVa; Adapter->LoopbackFramePhys[i] = BufferPa;
BufferVa += DC_LOOPBACK_FRAME_SIZE; BufferPa += DC_LOOPBACK_FRAME_SIZE; }
if (Adapter->Features & DC_HAS_POWER_MANAGEMENT) { Status = NdisAllocateMemoryWithTag((PVOID*)&Adapter->SetupFrameSaved, DC_SETUP_FRAME_SIZE, DC21X4_TAG); if (Status != NDIS_STATUS_SUCCESS) return Status; }
return NDIS_STATUS_SUCCESS;}
staticCODE_SEG("PAGE")NDIS_STATUSDcAllocateTransmitBuffers( _In_ PDC21X4_ADAPTER Adapter){ PDC_COALESCE_BUFFER CoalesceBuffer; NDIS_STATUS Status; ULONG i;
PAGED_CODE();
Status = NdisAllocateMemoryWithTag((PVOID*)&CoalesceBuffer, DC_TRANSMIT_BUFFERS * sizeof(*CoalesceBuffer), DC21X4_TAG); if (Status != NDIS_STATUS_SUCCESS) return Status;
NdisZeroMemory(CoalesceBuffer, DC_TRANSMIT_BUFFERS * sizeof(*CoalesceBuffer));
Adapter->CoalesceBuffer = CoalesceBuffer;
for (i = 0; i < DC_TRANSMIT_BUFFERS; ++i) { PVOID VirtualAddress; NDIS_PHYSICAL_ADDRESS PhysicalAddress;
NdisMAllocateSharedMemory(Adapter->AdapterHandle, DC_MEM_BLOCK_SIZE_TX_BUFFER, FALSE, /* Non-cached */ &VirtualAddress, &PhysicalAddress); if (!VirtualAddress) continue;
ASSERT(PhysicalAddress.HighPart == 0);
CoalesceBuffer->VirtualAddress = ALIGN_UP_POINTER_BY(VirtualAddress, SYSTEM_CACHE_ALIGNMENT_SIZE); CoalesceBuffer->PhysicalAddress = ALIGN_UP_BY(PhysicalAddress.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE);
Adapter->SendBufferData[i].PhysicalAddress.QuadPart = PhysicalAddress.QuadPart; Adapter->SendBufferData[i].VirtualAddress = VirtualAddress;
PushEntryList(&Adapter->SendBufferList, &CoalesceBuffer->ListEntry);
++CoalesceBuffer; }
if (!Adapter->SendBufferList.Next) return NDIS_STATUS_RESOURCES;
return NDIS_STATUS_SUCCESS;}
CODE_SEG("PAGE")VOIDDcInitTxRing( _In_ PDC21X4_ADAPTER Adapter){ PDC_TCB Tcb; PDC_TBD Tbd;
PAGED_CODE();
InitializeListHead(&Adapter->SendQueueList);
Tcb = Adapter->HeadTcb;
Adapter->CurrentTcb = Tcb; Adapter->LastTcb = Tcb;
Adapter->TcbSlots = DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE; Adapter->TbdSlots = DC_TRANSMIT_DESCRIPTORS - DC_TBD_RESERVE; Adapter->LoopbackFrameSlots = DC_LOOPBACK_FRAMES; Adapter->TcbCompleted = 0;
Tbd = Adapter->HeadTbd; Adapter->CurrentTbd = Tbd;
NdisZeroMemory(Tbd, sizeof(*Tbd) * DC_TRANSMIT_DESCRIPTORS);
Adapter->TailTbd->Control |= DC_TBD_CONTROL_END_OF_RING;}
staticCODE_SEG("PAGE")VOIDDcCreateRxRing( _In_ PDC21X4_ADAPTER Adapter){ PDC_RCB* RcbSlot; PDC_RCB Rcb; PDC_RBD Rbd; PSINGLE_LIST_ENTRY Entry;
PAGED_CODE();
Rbd = Adapter->HeadRbd; Adapter->CurrentRbd = Rbd;
RcbSlot = DC_GET_RCB_SLOT(Adapter, Rbd); Rcb = (PDC_RCB)Adapter->UsedRcbList.Next;
for (Entry = Adapter->UsedRcbList.Next; Entry != NULL; Entry = Entry->Next) { Rcb = (PDC_RCB)Entry;
C_ASSERT((DC_RECEIVE_BUFFER_SIZE % DC_RECEIVE_BUFFER_SIZE_MULTIPLE) == 0);
Rbd->Address1 = Rcb->PhysicalAddress; Rbd->Address2 = 0; Rbd->Control = DC_RECEIVE_BUFFER_SIZE; Rbd->Status = DC_RBD_STATUS_OWNED;
*RcbSlot = Rcb;
++RcbSlot; ++Rbd; Rcb = (PDC_RCB)Rcb->ListEntry.Next; } Rbd = Rbd - 1; Rbd->Control |= DC_RBD_CONTROL_CHAINED; Rbd->Address2 = Adapter->RbdPhys;
ASSERT(Rbd == Adapter->TailRbd);}
CODE_SEG("PAGE")VOIDDcInitRxRing( _In_ PDC21X4_ADAPTER Adapter){ PDC_RBD Rbd; ULONG i;
PAGED_CODE();
Rbd = Adapter->HeadRbd; Adapter->CurrentRbd = Rbd;
for (i = 0; i < Adapter->RcbCount; ++i) { Rbd->Control = DC_RECEIVE_BUFFER_SIZE; Rbd->Status = DC_RBD_STATUS_OWNED;
++Rbd; } Rbd = Rbd - 1; Rbd->Control |= DC_RBD_CONTROL_CHAINED;
ASSERT(Rbd == Adapter->TailRbd);}
staticCODE_SEG("PAGE")NDIS_STATUSDcAllocateMemory( _In_ PDC21X4_ADAPTER Adapter){ NDIS_STATUS Status;
PAGED_CODE();
Status = NdisMInitializeScatterGatherDma(Adapter->AdapterHandle, FALSE, /* 32-bit DMA */ DC_TRANSMIT_BLOCK_SIZE); if (Status != NDIS_STATUS_SUCCESS) return Status;
Status = DcAllocateReceiveDescriptors(Adapter); if (Status != NDIS_STATUS_SUCCESS) return Status;
Status = DcAllocateTransmitBlocks(Adapter); if (Status != NDIS_STATUS_SUCCESS) return Status;
Status = DcAllocateTransmitBuffers(Adapter); if (Status != NDIS_STATUS_SUCCESS) return Status;
Status = DcAllocateTransmitDescriptorsAndBuffers(Adapter); if (Status != NDIS_STATUS_SUCCESS) return Status;
Status = DcAllocateReceiveBuffers(Adapter); if (Status != NDIS_STATUS_SUCCESS) return Status;
NdisAllocateSpinLock(&Adapter->SendLock); NdisAllocateSpinLock(&Adapter->ReceiveLock); NdisAllocateSpinLock(&Adapter->ModeLock);
return NDIS_STATUS_SUCCESS;}
staticCODE_SEG("PAGE")VOIDDcInitTestPacket( _In_ PDC21X4_ADAPTER Adapter){ ULONG i;
PAGED_CODE();
for (i = 0; i < DC_LOOPBACK_FRAMES; ++i) { PETH_HEADER PacketBuffer = Adapter->LoopbackFrame[i];
NdisZeroMemory(PacketBuffer, DC_LOOPBACK_FRAME_SIZE);
/* Destination MAC address */ NdisMoveMemory(PacketBuffer->Destination, Adapter->CurrentMacAddress, ETH_LENGTH_OF_ADDRESS);
/* Source MAC address */ NdisMoveMemory(PacketBuffer->Source, Adapter->CurrentMacAddress, ETH_LENGTH_OF_ADDRESS);
++PacketBuffer; }}
staticCODE_SEG("PAGE")NDIS_STATUSDcInitializeAdapterResources( _In_ PDC21X4_ADAPTER Adapter){ NDIS_STATUS Status; PNDIS_RESOURCE_LIST AssignedResources = NULL; PCM_PARTIAL_RESOURCE_DESCRIPTOR IoDescriptor = NULL; PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDescriptor = NULL; UINT i, ResourceListSize = 0;
PAGED_CODE();
NdisMQueryAdapterResources(&Status, Adapter->WrapperConfigurationHandle, AssignedResources, &ResourceListSize); if (Status != NDIS_STATUS_RESOURCES) return NDIS_STATUS_FAILURE;
Status = NdisAllocateMemoryWithTag((PVOID*)&AssignedResources, ResourceListSize, DC21X4_TAG); if (Status != NDIS_STATUS_SUCCESS) return Status;
NdisMQueryAdapterResources(&Status, Adapter->WrapperConfigurationHandle, AssignedResources, &ResourceListSize); if (Status != NDIS_STATUS_SUCCESS) goto Cleanup;
for (i = 0; i < AssignedResources->Count; ++i) { PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
Descriptor = &AssignedResources->PartialDescriptors[i]; switch (Descriptor->Type) { case CmResourceTypePort: case CmResourceTypeMemory: { if (!IoDescriptor && (Descriptor->u.Port.Length == DC_IO_LENGTH)) IoDescriptor = Descriptor; break; }
case CmResourceTypeInterrupt: { if (!InterruptDescriptor) InterruptDescriptor = Descriptor; break; }
default: break; } }
if (!IoDescriptor || !InterruptDescriptor) { Status = NDIS_STATUS_RESOURCES; goto Cleanup; }
Adapter->InterruptVector = InterruptDescriptor->u.Interrupt.Vector; Adapter->InterruptLevel = InterruptDescriptor->u.Interrupt.Level; Adapter->InterruptFlags = InterruptDescriptor->Flags; if (InterruptDescriptor->ShareDisposition == CmResourceShareShared) Adapter->Flags |= DC_IRQ_SHARED;
Adapter->IoBaseAddress = IoDescriptor->u.Port.Start;
if ((IoDescriptor->Type == CmResourceTypePort) && (IoDescriptor->Flags & CM_RESOURCE_PORT_IO)) { Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->IoBase, Adapter->AdapterHandle, Adapter->IoBaseAddress.LowPart, DC_IO_LENGTH); } else { Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase, Adapter->AdapterHandle, Adapter->IoBaseAddress, DC_IO_LENGTH);
Adapter->Flags |= DC_IO_MAPPED; } if (Status != NDIS_STATUS_SUCCESS) goto Cleanup;
INFO("IO Base %p\n", Adapter->IoBase); INFO("IRQ Level %u, Vector %u\n", Adapter->InterruptLevel, Adapter->InterruptVector); INFO("IRQ ShareDisposition %u, InterruptFlags %lx\n", InterruptDescriptor->ShareDisposition, InterruptDescriptor->Flags);
Cleanup: NdisFreeMemory(AssignedResources, ResourceListSize, 0);
return Status;}
staticCODE_SEG("PAGE")NDIS_STATUSDcInitializeAdapterLocation( _In_ PDC21X4_ADAPTER Adapter){ PDEVICE_OBJECT Pdo; NTSTATUS Status; ULONG PropertyValue, Length;
PAGED_CODE();
NdisMGetDeviceProperty(Adapter->AdapterHandle, &Pdo, NULL, NULL, NULL, NULL);
Status = IoGetDeviceProperty(Pdo, DevicePropertyAddress, sizeof(PropertyValue), &PropertyValue, &Length); if (!NT_SUCCESS(Status)) return NDIS_STATUS_FAILURE;
/* We need this for PCI devices only ((DeviceNumber << 16) | Function) */ Adapter->DeviceNumber = (PropertyValue >> 16) & 0x000000FF;
Status = IoGetDeviceProperty(Pdo, DevicePropertyBusNumber, sizeof(PropertyValue), &Adapter->BusNumber, &Length); if (!NT_SUCCESS(Status)) return NDIS_STATUS_FAILURE;
return NDIS_STATUS_SUCCESS;}
staticCODE_SEG("PAGE")ULONGDcGetBusModeParameters( _In_ PDC21X4_ADAPTER Adapter, _In_ PPCI_COMMON_CONFIG PciData){ ULONG DefaultMode, NewMode;
PAGED_CODE();
/* TODO: Other architectures than x86 */ DefaultMode = DC_BUS_MODE_CACHE_ALIGNMENT_16 | DC_BUS_MODE_BURST_LENGTH_NO_LIMIT;
if (!(Adapter->Features & DC_ENABLE_PCI_COMMANDS)) return DefaultMode;
INFO("PCI Cache Line Size %u\n", PciData->CacheLineSize * 4); INFO("PCI Command %04lx\n", PciData->Command);
/* Use the cache line size if it was set up by firmware */ switch (PciData->CacheLineSize) { case 8: NewMode = DC_BUS_MODE_CACHE_ALIGNMENT_8 | DC_BUS_MODE_BURST_LENGTH_8; break; case 16: NewMode = DC_BUS_MODE_CACHE_ALIGNMENT_16 | DC_BUS_MODE_BURST_LENGTH_16; break; case 32: NewMode = DC_BUS_MODE_CACHE_ALIGNMENT_32 | DC_BUS_MODE_BURST_LENGTH_32; break;
default: return DefaultMode; }
/* Enable one of those commands */ if (PciData->Command & PCI_ENABLE_WRITE_AND_INVALIDATE) { NewMode |= DC_BUS_MODE_WRITE_INVALIDATE; } else { NewMode |= DC_BUS_MODE_READ_LINE; }
return NewMode;}
staticCODE_SEG("PAGE")NDIS_STATUSDcRecognizeHardware( _In_ PDC21X4_ADAPTER Adapter){ UCHAR Buffer[RTL_SIZEOF_THROUGH_FIELD(PCI_COMMON_CONFIG, CacheLineSize)]; PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)Buffer; // Partial PCI header PNDIS_TIMER_FUNCTION MediaMonitorRoutine; ULONG Bytes;
PAGED_CODE();
Bytes = NdisReadPciSlotInformation(Adapter->AdapterHandle, 0, FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID), Buffer, sizeof(Buffer)); if (Bytes != sizeof(Buffer)) return NDIS_STATUS_FAILURE;
Adapter->DeviceId = PciConfig->DeviceID; Adapter->RevisionId = PciConfig->RevisionID;
switch ((PciConfig->DeviceID << 16) | PciConfig->VendorID) { case DC_DEV_DECCHIP_21040: { Adapter->ChipType = DC21040; Adapter->InterruptMask = DC_GENERIC_IRQ_MASK | DC_IRQ_LINK_FAIL; Adapter->LinkStateChangeMask = DC_IRQ_LINK_FAIL; Adapter->HandleLinkStateChange = MediaLinkStateChange21040; MediaMonitorRoutine = MediaMonitor21040Dpc; break; }
case DC_DEV_DECCHIP_21041: { Adapter->ChipType = DC21041; Adapter->Features |= DC_HAS_POWER_SAVING | DC_HAS_TIMER; Adapter->InterruptMask = DC_GENERIC_IRQ_MASK | DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL; Adapter->LinkStateChangeMask = DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL; Adapter->HandleLinkStateChange = MediaLinkStateChange21041; MediaMonitorRoutine = MediaMonitor21041Dpc; break; }
case DC_DEV_DECCHIP_21140: { Adapter->ChipType = DC21140; Adapter->Features |= DC_HAS_TIMER;
if ((PciConfig->RevisionID & 0xF0) < 0x20) { /* 21140 */ Adapter->Features |= DC_PERFECT_FILTERING_ONLY; } else { /* 21140A */ Adapter->Features |= DC_NEED_RX_OVERFLOW_WORKAROUND | DC_ENABLE_PCI_COMMANDS | DC_HAS_POWER_SAVING; }
Adapter->OpMode |= DC_OPMODE_PORT_ALWAYS; Adapter->InterruptMask = DC_GENERIC_IRQ_MASK; MediaMonitorRoutine = MediaMonitor21140Dpc; break; }
case DC_DEV_INTEL_21143: { Adapter->Features |= DC_NEED_RX_OVERFLOW_WORKAROUND | DC_SIA_GPIO | DC_HAS_POWER_SAVING | DC_MII_AUTOSENSE | DC_HAS_TIMER;
Adapter->InterruptMask = DC_GENERIC_IRQ_MASK | DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL; Adapter->LinkStateChangeMask = DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL;
Adapter->ChipType = DC21143;
if ((PciConfig->RevisionID & 0xF0) < 0x20) { /* 21142 */ } else { /* 21143 */ Adapter->Features |= DC_ENABLE_PCI_COMMANDS; Adapter->OpMode |= DC_OPMODE_PORT_ALWAYS; Adapter->InterruptMask |= DC_IRQ_LINK_CHANGED; Adapter->LinkStateChangeMask |= DC_IRQ_LINK_CHANGED; }
/* 21143 -PD and -TD */ if ((PciConfig->RevisionID & 0xF0) > 0x30) Adapter->Features |= DC_HAS_POWER_MANAGEMENT;
Adapter->HandleLinkStateChange = MediaLinkStateChange21143; MediaMonitorRoutine = MediaMonitor21143Dpc; break; }
case DC_DEV_INTEL_21145: { Adapter->ChipType = DC21145;
Adapter->Features |= DC_NEED_RX_OVERFLOW_WORKAROUND | DC_SIA_GPIO | DC_HAS_POWER_MANAGEMENT | DC_HAS_POWER_SAVING | DC_SIA_ANALOG_CONTROL | DC_ENABLE_PCI_COMMANDS | DC_MII_AUTOSENSE | DC_HAS_TIMER;
Adapter->OpMode |= DC_OPMODE_PORT_ALWAYS; Adapter->InterruptMask = DC_GENERIC_IRQ_MASK | DC_IRQ_LINK_CHANGED | DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL; Adapter->LinkStateChangeMask = DC_IRQ_LINK_CHANGED | DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL; Adapter->HandleLinkStateChange = MediaLinkStateChange21143; MediaMonitorRoutine = MediaMonitor21143Dpc;
Adapter->AnalogControl = DC_HPNA_ANALOG_CTRL;
/* Workaround for internal RX errata */ Adapter->HpnaRegister[HPNA_NOISE_FLOOR] = 0x10; Adapter->HpnaInitBitmap = (1 << HPNA_NOISE_FLOOR); break; }
default: return NDIS_STATUS_NOT_RECOGNIZED; }
Adapter->BusMode = DcGetBusModeParameters(Adapter, PciConfig);
INFO("Bus Mode %08lx\n", Adapter->BusMode);
/* Errata: hash filtering is broken on some chips */ if (Adapter->Features & DC_PERFECT_FILTERING_ONLY) Adapter->MulticastMaxEntries = DC_SETUP_FRAME_ADDRESSES; else Adapter->MulticastMaxEntries = DC_MULTICAST_LIST_SIZE;
NdisMInitializeTimer(&Adapter->MediaMonitorTimer, Adapter->AdapterHandle, MediaMonitorRoutine, Adapter);
return NDIS_STATUS_SUCCESS;}
CODE_SEG("PAGE")VOIDDcFreeAdapter( _In_ __drv_freesMem(Mem) PDC21X4_ADAPTER Adapter){ ULONG i;
PAGED_CODE();
DcFreeEeprom(Adapter);
if (Adapter->Interrupt.InterruptObject) { NdisMDeregisterInterrupt(&Adapter->Interrupt); }
if (Adapter->IoBase) { if (Adapter->Flags & DC_IO_MAPPED) { NdisMUnmapIoSpace(Adapter->AdapterHandle, Adapter->IoBase, DC_IO_LENGTH); } else { NdisMDeregisterIoPortRange(Adapter->AdapterHandle, Adapter->IoBaseAddress.LowPart, DC_IO_LENGTH, Adapter->IoBase); } }
if (Adapter->HeadTcb) { NdisFreeMemory(Adapter->HeadTcb, sizeof(DC_TCB) * DC_TRANSMIT_BLOCKS, 0); } if (Adapter->RcbArray) { NdisFreeMemory(Adapter->RcbArray, sizeof(PVOID) * Adapter->RcbCount, 0); } if (Adapter->SetupFrameSaved) { NdisFreeMemory(Adapter->SetupFrameSaved, DC_SETUP_FRAME_SIZE, 0); }
while (Adapter->AllocRcbList.Next) { PSINGLE_LIST_ENTRY Entry = PopEntryList(&Adapter->AllocRcbList); PDC_RCB Rcb = CONTAINING_RECORD(Entry, DC_RCB, AllocListEntry);
DcFreeRcb(Adapter, Rcb); }
if (Adapter->RbdOriginal) { NdisMFreeSharedMemory(Adapter->AdapterHandle, DC_MEM_BLOCK_SIZE_RBD, FALSE, /* Non-cached */ Adapter->RbdOriginal, Adapter->RbdPhysOriginal); } if (Adapter->TbdOriginal) { NdisMFreeSharedMemory(Adapter->AdapterHandle, DC_MEM_BLOCK_SIZE_TBD_AUX, FALSE, /* Non-cached */ Adapter->TbdOriginal, Adapter->TbdPhysOriginal); } if (Adapter->CoalesceBuffer) { for (i = 0; i < DC_TRANSMIT_BUFFERS; ++i) { PDC_TX_BUFFER_DATA SendBufferData = &Adapter->SendBufferData[i];
if (!SendBufferData->VirtualAddress) continue;
NdisMFreeSharedMemory(Adapter->AdapterHandle, DC_MEM_BLOCK_SIZE_TX_BUFFER, FALSE, /* Non-cached */ SendBufferData->VirtualAddress, SendBufferData->PhysicalAddress); } }
if (Adapter->PacketPool) NdisFreePacketPool(Adapter->PacketPool); if (Adapter->BufferPool) NdisFreeBufferPool(Adapter->BufferPool);
if (Adapter->SendLock.SpinLock) NdisFreeSpinLock(&Adapter->SendLock); if (Adapter->ReceiveLock.SpinLock) NdisFreeSpinLock(&Adapter->ReceiveLock); if (Adapter->ModeLock.SpinLock) NdisFreeSpinLock(&Adapter->ModeLock);
NdisFreeMemory(Adapter->AdapterOriginal, sizeof(*Adapter), 0);}
CODE_SEG("PAGE")NDIS_STATUSNTAPIDcInitialize( _Out_ PNDIS_STATUS OpenErrorStatus, _Out_ PUINT SelectedMediumIndex, _In_ PNDIS_MEDIUM MediumArray, _In_ UINT MediumArraySize, _In_ NDIS_HANDLE MiniportAdapterHandle, _In_ NDIS_HANDLE WrapperConfigurationContext){ PDC21X4_ADAPTER Adapter; PVOID UnalignedAdapter; NDIS_STATUS Status; ULONG Alignment, AdapterSize, OpMode; BOOLEAN Success; UINT i;
INFO("Called\n");
PAGED_CODE();
for (i = 0; i < MediumArraySize; ++i) { if (MediumArray[i] == NdisMedium802_3) { *SelectedMediumIndex = i; break; } } if (i == MediumArraySize) { ERR("No supported media\n"); return NDIS_STATUS_UNSUPPORTED_MEDIA; }
Alignment = NdisGetSharedDataAlignment(); AdapterSize = sizeof(*Adapter) + Alignment;
Status = NdisAllocateMemoryWithTag((PVOID*)&UnalignedAdapter, AdapterSize, DC21X4_TAG); if (Status != NDIS_STATUS_SUCCESS) { ERR("Failed to allocate adapter context\n"); return NDIS_STATUS_RESOURCES; } NdisZeroMemory(UnalignedAdapter, AdapterSize);
Adapter = ALIGN_UP_POINTER_BY(UnalignedAdapter, Alignment); Adapter->AdapterOriginal = UnalignedAdapter; Adapter->AdapterSize = AdapterSize; Adapter->AdapterHandle = MiniportAdapterHandle; Adapter->WrapperConfigurationHandle = WrapperConfigurationContext;
NdisInitializeWorkItem(&Adapter->ResetWorkItem, DcResetWorker, Adapter); NdisInitializeWorkItem(&Adapter->PowerWorkItem, DcPowerWorker, Adapter); NdisInitializeWorkItem(&Adapter->TxRecoveryWorkItem, DcTransmitTimeoutRecoveryWorker, Adapter);
NdisMSetAttributesEx(MiniportAdapterHandle, Adapter, 2, /* CheckForHangTimeInSeconds */ NDIS_ATTRIBUTE_BUS_MASTER | NDIS_ATTRIBUTE_DESERIALIZE | NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS, NdisInterfacePci);
Status = DcRecognizeHardware(Adapter); if (Status != NDIS_STATUS_SUCCESS) { return Status; }
Status = DcInitializeAdapterResources(Adapter); if (Status != NDIS_STATUS_SUCCESS) { goto Failure; }
Status = DcInitializeAdapterLocation(Adapter); if (Status != NDIS_STATUS_SUCCESS) { goto Failure; }
/* Bring the chip out of sleep mode */ DcPowerSave(Adapter, FALSE);
OpMode = DC_READ(Adapter, DcCsr6_OpMode); OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE); DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
MediaInitMediaList(Adapter);
Status = DcReadEeprom(Adapter); if (Status != NDIS_STATUS_SUCCESS) { goto Failure; }
NdisMoveMemory(Adapter->CurrentMacAddress, Adapter->PermanentMacAddress, ETH_LENGTH_OF_ADDRESS);
Status = DcReadConfiguration(Adapter); if (Status != NDIS_STATUS_SUCCESS) { goto Failure; }
Status = DcAllocateMemory(Adapter); if (Status != NDIS_STATUS_SUCCESS) { goto Failure; }
DcInitTestPacket(Adapter);
DcCreateRxRing(Adapter);
/* Execute the reset sequence */ if (Adapter->ResetStreamLength) { for (i = 0; i < Adapter->ResetStreamLength; ++i) { DcWriteGpio(Adapter, Adapter->ResetStream[i]); NdisMSleep(100); }
/* Give the PHY some time to reset */ NdisMSleep(5000); }
/* Perform a software reset */ DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET); NdisMSleep(100); DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode);
/* Try to detect a MII PHY */ if (Adapter->Features & DC_HAS_MII) { MediaSelectMiiPort(Adapter, TRUE);
Success = DcFindMiiPhy(Adapter); if (Success) { /* Disable all link interrupts when the MII PHY media is found */ Adapter->InterruptMask &= ~(DC_IRQ_LINK_CHANGED | DC_IRQ_LINK_FAIL | DC_IRQ_LINK_PASS); Adapter->LinkStateChangeMask = 0; } else { /* Incorrect EEPROM table or PHY is not connected, switch to a serial transceiver */ WARN("No PHY devices found\n"); Adapter->Features &= ~DC_HAS_MII; } }
MediaInitDefaultMedia(Adapter, Adapter->DefaultMedia);
/* Set the MAC address */ DcSetupFrameInitialize(Adapter);
/* Clear statistics */ DC_READ(Adapter, DcCsr8_RxCounters);
Adapter->Flags |= DC_FIRST_SETUP;
Status = DcSetupAdapter(Adapter); if (Status != NDIS_STATUS_SUCCESS) { ERR("Failed to initialize the NIC\n"); goto Disable; }
Adapter->Flags &= ~DC_FIRST_SETUP;
Status = NdisMRegisterInterrupt(&Adapter->Interrupt, Adapter->AdapterHandle, Adapter->InterruptVector, Adapter->InterruptLevel, TRUE, /* Request ISR calls */ !!(Adapter->Flags & DC_IRQ_SHARED), (Adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ? NdisInterruptLatched : NdisInterruptLevelSensitive); if (Status != NDIS_STATUS_SUCCESS) { ERR("Unable to register interrupt\n"); goto Disable; }
DcStartAdapter(Adapter);
return NDIS_STATUS_SUCCESS;
Disable: DcDisableHw(Adapter);Failure: ERR("Initialization failed with status %08lx\n", Status);
DcFreeAdapter(Adapter);
return Status;}