12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- dwcethhw.c
- Abstract:
- This module implements the actual hardware support for the DesignWare
- Ethernet controller.
- Author:
- Evan Green 5-Dec-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/net/netdrv.h>
- #include <minoca/net/mii.h>
- #include "dwceth.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Borrow an unused bit in the status register for the software link check.
- //
- #define DWE_STATUS_LINK_CHECK (1 << 11)
- //
- // Define the maximum amount of packets that DWE will keep queued before it
- // starts to drop packets.
- //
- #define DWE_MAX_TRANSMIT_PACKET_LIST_COUNT (DWE_TRANSMIT_DESCRIPTOR_COUNT * 2)
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- DwepLinkCheckDpc (
- PDPC Dpc
- );
- KSTATUS
- DwepInitializePhy (
- PDWE_DEVICE Device
- );
- VOID
- DwepReadMacAddress (
- PDWE_DEVICE Device
- );
- VOID
- DwepReapCompletedTransmitDescriptors (
- PDWE_DEVICE Device
- );
- VOID
- DwepSendPendingPackets (
- PDWE_DEVICE Device
- );
- VOID
- DwepReapReceivedFrames (
- PDWE_DEVICE Device
- );
- KSTATUS
- DwepCheckLink (
- PDWE_DEVICE Device
- );
- KSTATUS
- DwepDetermineLinkParameters (
- PDWE_DEVICE Device,
- PBOOL LinkUp,
- PULONGLONG Speed,
- PBOOL FullDuplex
- );
- KSTATUS
- DwepReadMii (
- PDWE_DEVICE Device,
- ULONG Phy,
- ULONG Register,
- PULONG Result
- );
- KSTATUS
- DwepWriteMii (
- PDWE_DEVICE Device,
- ULONG Phy,
- ULONG Register,
- ULONG Value
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- BOOL DweDisablePacketDropping = FALSE;
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- DweSend (
- PVOID DeviceContext,
- PNET_PACKET_LIST PacketList
- )
- /*++
- Routine Description:
- This routine sends data through the network.
- Arguments:
- DeviceContext - Supplies a pointer to the device context associated with
- the link down which this data is to be sent.
- PacketList - Supplies a pointer to a list of network packets to send. Data
- in these packets may be modified by this routine, but must not be used
- once this routine returns.
- Return Value:
- STATUS_SUCCESS if all packets were sent.
- STATUS_RESOURCE_IN_USE if some or all of the packets were dropped due to
- the hardware being backed up with too many packets to send.
- Other failure codes indicate that none of the packets were sent.
- --*/
- {
- PDWE_DEVICE Device;
- UINTN PacketListCount;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- Device = (PDWE_DEVICE)DeviceContext;
- KeAcquireQueuedLock(Device->TransmitLock);
- if (Device->LinkActive == FALSE) {
- Status = STATUS_NO_NETWORK_CONNECTION;
- goto SendEnd;
- }
- //
- // If there is any room in the packet list (or dropping packets is
- // disabled), add all of the packets to the list waiting to be sent.
- //
- PacketListCount = Device->TransmitPacketList.Count;
- if ((PacketListCount < DWE_MAX_TRANSMIT_PACKET_LIST_COUNT) ||
- (DweDisablePacketDropping != FALSE)) {
- NET_APPEND_PACKET_LIST(PacketList, &(Device->TransmitPacketList));
- DwepSendPendingPackets(Device);
- Status = STATUS_SUCCESS;
- //
- // Otherwise report that the resource is use as it is too busy to handle
- // more packets.
- //
- } else {
- Device->DroppedTxPackets += PacketList->Count;
- RtlDebugPrint("DWE: Dropped %d packets.\n", Device->DroppedTxPackets);
- Status = STATUS_RESOURCE_IN_USE;
- }
- SendEnd:
- KeReleaseQueuedLock(Device->TransmitLock);
- return Status;
- }
- KSTATUS
- DweGetSetInformation (
- PVOID DeviceContext,
- NET_LINK_INFORMATION_TYPE InformationType,
- PVOID Data,
- PUINTN DataSize,
- BOOL Set
- )
- /*++
- Routine Description:
- This routine gets or sets the network device layer's link information.
- Arguments:
- DeviceContext - Supplies a pointer to the device context associated with
- the link for which information is being set or queried.
- InformationType - Supplies the type of information being queried or set.
- Data - Supplies a pointer to the data buffer where the data is either
- returned for a get operation or given for a set operation.
- DataSize - Supplies a pointer that on input contains the size of the data
- buffer. On output, contains the required size of the data buffer.
- Set - Supplies a boolean indicating if this is a get operation (FALSE) or a
- set operation (TRUE).
- Return Value:
- Status code.
- --*/
- {
- ULONG ChangedFlags;
- PDWE_DEVICE Device;
- PULONG Flags;
- KSTATUS Status;
- ULONG Value;
- Device = DeviceContext;
- switch (InformationType) {
- case NetLinkInformationChecksumOffload:
- if (*DataSize != sizeof(ULONG)) {
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- //
- // If the request is a get, just return the device's current checksum
- // flags.
- //
- Status = STATUS_SUCCESS;
- Flags = (PULONG)Data;
- if (Set == FALSE) {
- *Flags = Device->ChecksumFlags;
- break;
- }
- //
- // Synchronize on the receive lock. There is nothing to do for transmit
- // changes, so leave that lock out of it.
- //
- KeAcquireQueuedLock(Device->ReceiveLock);
- //
- // If it is a set, figure out what is changing. There is nothing to do
- // if the change is in the transmit flags. Netcore requests transmit
- // offloads on a per-packet basis. Requests to enable or disable
- // receive checksum change the MAC configuration.
- //
- ChangedFlags = *Flags ^ Device->ChecksumFlags;
- if ((ChangedFlags & NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK) != 0) {
- //
- // If any of the receive checksum flags are set, then
- // offloading must remain on for all protocols. There is no
- // granularity.
- //
- Value = DWE_READ(Device, DweRegisterMacConfiguration);
- if ((*Flags & NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK) != 0) {
- Value |= DWE_MAC_CONFIGURATION_CHECKSUM_OFFLOAD;
- //
- // Otherwise, if all flags are off and something was previously
- // set, turn receive checksum offloadng off.
- //
- } else if ((*Flags & NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK) == 0) {
- Value &= ~DWE_MAC_CONFIGURATION_CHECKSUM_OFFLOAD;
- }
- DWE_WRITE(Device, DweRegisterMacConfiguration, Value);
- }
- //
- // Update the checksum flags.
- //
- Device->ChecksumFlags = *Flags;
- KeReleaseQueuedLock(Device->ReceiveLock);
- break;
- default:
- Status = STATUS_NOT_SUPPORTED;
- break;
- }
- return Status;
- }
- KSTATUS
- DwepInitializeDeviceStructures (
- PDWE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine creates the data structures needed for a DesignWare Ethernet
- controller.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- ULONG CommandIndex;
- PDWE_DESCRIPTOR Descriptor;
- ULONG DescriptorPhysical;
- ULONG DescriptorSize;
- ULONG FrameIndex;
- ULONG IoBufferFlags;
- ULONG NextDescriptorPhysical;
- ULONG ReceiveFrameData;
- ULONG ReceiveSize;
- KSTATUS Status;
- //
- // Initialize the transmit and receive list locks.
- //
- Device->TransmitLock = KeCreateQueuedLock();
- if (Device->TransmitLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- Device->ReceiveLock = KeCreateQueuedLock();
- if (Device->ReceiveLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- //
- // Allocate the receive buffers. This is allocated as non-write though and
- // cacheable, which means software must be careful when the frame is
- // first received (and do an invalidate), and when setting up the
- // link pointers, but after the receive is complete it's normal memory.
- //
- ReceiveSize = DWE_RECEIVE_FRAME_DATA_SIZE * DWE_RECEIVE_FRAME_COUNT;
- ASSERT(Device->ReceiveDataIoBuffer == NULL);
- IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
- Device->ReceiveDataIoBuffer = MmAllocateNonPagedIoBuffer(0,
- MAX_ULONG,
- 16,
- ReceiveSize,
- IoBufferFlags);
- if (Device->ReceiveDataIoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- ASSERT(Device->ReceiveDataIoBuffer->FragmentCount == 1);
- ASSERT(Device->ReceiveDataIoBuffer->Fragment[0].VirtualAddress != NULL);
- Device->ReceiveData =
- Device->ReceiveDataIoBuffer->Fragment[0].VirtualAddress;
- //
- // Allocate both the transmit and the receive descriptors. This is
- // allocated non-cached as they are shared with the hardware.
- //
- DescriptorSize = (DWE_TRANSMIT_DESCRIPTOR_COUNT + DWE_RECEIVE_FRAME_COUNT) *
- sizeof(DWE_DESCRIPTOR);
- ASSERT(Device->DescriptorIoBuffer == NULL);
- IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
- Device->DescriptorIoBuffer = MmAllocateNonPagedIoBuffer(0,
- MAX_ULONG,
- 16,
- DescriptorSize,
- IoBufferFlags);
- if (Device->DescriptorIoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- ASSERT(Device->DescriptorIoBuffer->FragmentCount == 1);
- ASSERT(Device->DescriptorIoBuffer->Fragment[0].VirtualAddress != NULL);
- Device->TransmitDescriptors =
- Device->DescriptorIoBuffer->Fragment[0].VirtualAddress;
- Device->ReceiveDescriptors = Device->TransmitDescriptors +
- DWE_TRANSMIT_DESCRIPTOR_COUNT;
- NET_INITIALIZE_PACKET_LIST(&(Device->TransmitPacketList));
- Device->TransmitBegin = 0;
- Device->TransmitEnd = 0;
- Device->ReceiveBegin = 0;
- RtlZeroMemory(Device->TransmitDescriptors, DescriptorSize);
- //
- // Allocate an array of pointers to net packet buffers that runs parallel
- // to the transmit array.
- //
- AllocationSize = sizeof(PNET_PACKET_BUFFER) * DWE_TRANSMIT_DESCRIPTOR_COUNT;
- Device->TransmitPacket = MmAllocateNonPagedPool(AllocationSize,
- DWE_ALLOCATION_TAG);
- if (Device->TransmitPacket == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- RtlZeroMemory(Device->TransmitPacket, AllocationSize);
- ASSERT(Device->WorkItem == NULL);
- Device->WorkItem = KeCreateWorkItem(
- NULL,
- WorkPriorityNormal,
- (PWORK_ITEM_ROUTINE)DwepInterruptServiceWorker,
- Device,
- DWE_ALLOCATION_TAG);
- if (Device->WorkItem == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- ASSERT(Device->LinkCheckTimer == NULL);
- Device->LinkCheckTimer = KeCreateTimer(DWE_ALLOCATION_TAG);
- if (Device->LinkCheckTimer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- Device->LinkCheckDpc = KeCreateDpc(DwepLinkCheckDpc, Device);
- if (Device->LinkCheckDpc == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- //
- // Initialize the receive frame list in chained mode.
- //
- DescriptorPhysical =
- (ULONG)(Device->DescriptorIoBuffer->Fragment[0].PhysicalAddress);
- DescriptorPhysical += sizeof(DWE_DESCRIPTOR) *
- DWE_TRANSMIT_DESCRIPTOR_COUNT;
- NextDescriptorPhysical = DescriptorPhysical + sizeof(DWE_DESCRIPTOR);
- ReceiveFrameData =
- (ULONG)(Device->ReceiveDataIoBuffer->Fragment[0].PhysicalAddress);
- for (FrameIndex = 0;
- FrameIndex < DWE_RECEIVE_FRAME_COUNT;
- FrameIndex += 1) {
- Descriptor = &(Device->ReceiveDescriptors[FrameIndex]);
- Descriptor->Control = DWE_RX_STATUS_DMA_OWNED;
- Descriptor->BufferSize =
- DWE_BUFFER_SIZE(DWE_RECEIVE_FRAME_DATA_SIZE, 0) |
- DWE_RX_SIZE_CHAINED;
- Descriptor->Address1 = ReceiveFrameData;
- ReceiveFrameData += DWE_RECEIVE_FRAME_DATA_SIZE;
- if (FrameIndex == DWE_RECEIVE_FRAME_COUNT - 1) {
- Descriptor->Address2OrNextDescriptor = DescriptorPhysical;
- } else {
- Descriptor->Address2OrNextDescriptor = NextDescriptorPhysical;
- }
- NextDescriptorPhysical += sizeof(DWE_DESCRIPTOR);
- }
- //
- // Initialize the transmit descriptor list in chained mode. The "DMA owned"
- // bit is clear on all descriptors, so the controller doesn't try to
- // transmit them.
- //
- DescriptorPhysical =
- (ULONG)(Device->DescriptorIoBuffer->Fragment[0].PhysicalAddress);
- NextDescriptorPhysical = DescriptorPhysical + sizeof(DWE_DESCRIPTOR);
- for (CommandIndex = 0;
- CommandIndex < DWE_TRANSMIT_DESCRIPTOR_COUNT;
- CommandIndex += 1) {
- Descriptor = &(Device->TransmitDescriptors[CommandIndex]);
- Descriptor->Control = DWE_TX_CONTROL_CHAINED;
- //
- // Loop the last command back around to the first.
- //
- if (CommandIndex == DWE_TRANSMIT_DESCRIPTOR_COUNT - 1) {
- Descriptor->Address2OrNextDescriptor = DescriptorPhysical;
- //
- // Point this link at the next command.
- //
- } else {
- Descriptor->Address2OrNextDescriptor = NextDescriptorPhysical;
- }
- NextDescriptorPhysical += sizeof(DWE_DESCRIPTOR);
- }
- Status = STATUS_SUCCESS;
- InitializeDeviceStructuresEnd:
- if (!KSUCCESS(Status)) {
- if (Device->TransmitLock != NULL) {
- KeDestroyQueuedLock(Device->TransmitLock);
- Device->TransmitLock = NULL;
- }
- if (Device->ReceiveLock != NULL) {
- KeDestroyQueuedLock(Device->ReceiveLock);
- Device->ReceiveLock = NULL;
- }
- if (Device->ReceiveDataIoBuffer != NULL) {
- MmFreeIoBuffer(Device->ReceiveDataIoBuffer);
- Device->ReceiveDataIoBuffer = NULL;
- Device->ReceiveData = NULL;
- }
- if (Device->DescriptorIoBuffer != NULL) {
- MmFreeIoBuffer(Device->DescriptorIoBuffer);
- Device->DescriptorIoBuffer = NULL;
- Device->TransmitDescriptors = NULL;
- Device->ReceiveDescriptors = NULL;
- }
- if (Device->TransmitPacket != NULL) {
- MmFreeNonPagedPool(Device->TransmitPacket);
- Device->TransmitPacket = NULL;
- }
- if (Device->WorkItem != NULL) {
- KeDestroyWorkItem(Device->WorkItem);
- Device->WorkItem = NULL;
- }
- if (Device->LinkCheckTimer != NULL) {
- KeDestroyTimer(Device->LinkCheckTimer);
- Device->LinkCheckTimer = NULL;
- }
- if (Device->LinkCheckDpc != NULL) {
- KeDestroyDpc(Device->LinkCheckDpc);
- Device->LinkCheckDpc = NULL;
- }
- }
- return Status;
- }
- KSTATUS
- DwepResetDevice (
- PDWE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine resets the DesignWare Ethernet device.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- ULONG DescriptorBase;
- ULONGLONG Frequency;
- KSTATUS Status;
- ULONGLONG Timeout;
- ULONG Value;
- //
- // Read the MAC address before resetting the device to get a MAC address
- // that might have been assigned by the firmware.
- //
- DwepReadMacAddress(Device);
- //
- // Perform a software reset, and wait for it to finish.
- //
- Value = DWE_READ(Device, DweRegisterBusMode);
- Value |= DWE_BUS_MODE_SOFTWARE_RESET;
- DWE_WRITE(Device, DweRegisterBusMode, Value);
- Frequency = HlQueryTimeCounterFrequency();
- Timeout = KeGetRecentTimeCounter() + Frequency;
- do {
- Value = DWE_READ(Device, DweRegisterBusMode);
- if ((Value & DWE_BUS_MODE_SOFTWARE_RESET) == 0) {
- break;
- }
- KeYield();
- } while (KeGetRecentTimeCounter() <= Timeout);
- if ((Value & DWE_BUS_MODE_SOFTWARE_RESET) != 0) {
- RtlDebugPrint("DWE: Cannot reset device.\n");
- return STATUS_DEVICE_IO_ERROR;
- }
- Value |= DWE_BUS_MODE_LARGE_DESCRIPTORS |
- DWE_BUS_MODE_8X_BURST_LENGTHS |
- (DWE_BUS_MODE_TX_BURST_LENGTH <<
- DWE_BUS_MODE_TX_BURST_LENGTH_SHIFT);
- DWE_WRITE(Device, DweRegisterBusMode, Value);
- //
- // Halt any DMA.
- //
- Value = DWE_READ(Device, DweRegisterOperationMode);
- Value &= ~(DWE_OPERATION_MODE_START_RECEIVE |
- DWE_OPERATION_MODE_START_TRANSMIT);
- DWE_WRITE(Device, DweRegisterOperationMode, Value);
- //
- // Write the descriptor base addresses.
- //
- DescriptorBase =
- (ULONG)(Device->DescriptorIoBuffer->Fragment[0].PhysicalAddress);
- DWE_WRITE(Device, DweRegisterTransmitDescriptorListAddress, DescriptorBase);
- DescriptorBase += sizeof(DWE_DESCRIPTOR) * DWE_TRANSMIT_DESCRIPTOR_COUNT;
- DWE_WRITE(Device, DweRegisterReceiveDescriptorListAddress, DescriptorBase);
- //
- // Set the MAC address.
- //
- RtlCopyMemory(&Value, Device->MacAddress, sizeof(ULONG));
- DWE_WRITE(Device, DWE_MAC_ADDRESS_LOW(0), Value);
- Value = 0;
- RtlCopyMemory(&Value, &(Device->MacAddress[sizeof(ULONG)]), sizeof(USHORT));
- DWE_WRITE(Device, DWE_MAC_ADDRESS_HIGH(0), Value);
- Value = DWE_MAC_FRAME_FILTER_HASH_MULTICAST;
- DWE_WRITE(Device, DweRegisterMacFrameFilter, Value);
- //
- // Set up DMA.
- //
- Value = DWE_READ(Device, DweRegisterOperationMode);
- Value |= DWE_OPERATION_MODE_TX_STORE_AND_FORWARD |
- DWE_OPERATION_MODE_OPERATE_ON_SECOND_FRAME |
- DWE_OPERATION_MODE_FORWARD_UNDERSIZED_GOOD_FRAMES |
- DWE_OPERATION_MODE_RX_THRESHOLD_32;
- Value &= ~DWE_OPERATION_MODE_RX_STORE_AND_FORWARD;
- DWE_WRITE(Device, DweRegisterOperationMode, Value);
- DWE_WRITE(Device, DweRegisterInterruptEnable, DWE_INTERRUPT_ENABLE_DEFAULT);
- //
- // Disable interrupts that indicate when the counters get halfway or all
- // the way towards overflowing.
- //
- Value = DWE_RECEIVE_INTERRUPT_MASK;
- DWE_WRITE(Device, DweRegisterMmcReceiveInterruptMask, Value);
- Value = DWE_TRANSMIT_INTERRUPT_MASK;
- DWE_WRITE(Device, DweRegisterMmcTransmitInterruptMask, Value);
- Value = DWE_RECEIVE_CHECKSUM_INTERRUPT_MASK;
- DWE_WRITE(Device, DweRegisterReceiveChecksumOffloadInterruptMask, Value);
- //
- // Fire up DMA.
- //
- Value = DWE_READ(Device, DweRegisterOperationMode);
- Value |= DWE_OPERATION_MODE_START_TRANSMIT |
- DWE_OPERATION_MODE_START_RECEIVE;
- DWE_WRITE(Device, DweRegisterOperationMode, Value);
- //
- // Enable data flow.
- //
- Value = DWE_READ(Device, DweRegisterMacConfiguration);
- Value |= DWE_MAC_CONFIGURATION_JABBER_DISABLE |
- DWE_MAC_CONFIGURATION_AUTO_PAD_CRC_STRIPPING |
- DWE_MAC_CONFIGURATION_BURST_ENABLE |
- DWE_MAC_CONFIGURATION_TRANSMITTER_ENABLE |
- DWE_MAC_CONFIGURATION_RECEIVER_ENABLE;
- if ((Device->ChecksumFlags & NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK) != 0) {
- Value |= DWE_MAC_CONFIGURATION_CHECKSUM_OFFLOAD;
- } else {
- Value &= ~DWE_MAC_CONFIGURATION_CHECKSUM_OFFLOAD;
- }
- DWE_WRITE(Device, DweRegisterMacConfiguration, Value);
- Status = DwepInitializePhy(Device);
- if (!KSUCCESS(Status)) {
- goto ResetDeviceEnd;
- }
- //
- // Notify the networking core of this new link now that the device is ready
- // to send and receive data, pending media being present.
- //
- if (Device->NetworkLink == NULL) {
- Status = DwepAddNetworkDevice(Device);
- if (!KSUCCESS(Status)) {
- goto ResetDeviceEnd;
- }
- }
- //
- // Determine whether or not there is media connected, and what speed it is.
- //
- Status = DwepCheckLink(Device);
- if (!KSUCCESS(Status)) {
- goto ResetDeviceEnd;
- }
- //
- // Fire up the link check timer.
- //
- Device->LinkCheckInterval = Frequency * DWE_LINK_CHECK_INTERVAL;
- KeQueueTimer(Device->LinkCheckTimer,
- TimerQueueSoft,
- 0,
- Device->LinkCheckInterval,
- 0,
- Device->LinkCheckDpc);
- ResetDeviceEnd:
- return Status;
- }
- INTERRUPT_STATUS
- DwepInterruptService (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine implements the DesignWare Ethernet interrupt service routine.
- Arguments:
- Context - Supplies the context pointer given to the system when the
- interrupt was connected. In this case, this points to the e100 device
- structure.
- Return Value:
- Interrupt status.
- --*/
- {
- PDWE_DEVICE Device;
- INTERRUPT_STATUS InterruptStatus;
- ULONG PendingBits;
- Device = (PDWE_DEVICE)Context;
- InterruptStatus = InterruptStatusNotClaimed;
- //
- // Read the status register, and if anything's set add it to the pending
- // bits.
- //
- PendingBits = DWE_READ(Device, DweRegisterStatus);
- if (PendingBits != 0) {
- InterruptStatus = InterruptStatusClaimed;
- RtlAtomicOr32(&(Device->PendingStatusBits), PendingBits);
- //
- // Read the more detailed status register, and clear the bits.
- //
- DWE_WRITE(Device, DweRegisterStatus, PendingBits);
- if ((PendingBits & DWE_STATUS_ERROR_MASK) != 0) {
- RtlDebugPrint("DWE Error: %08x\n", PendingBits);
- }
- }
- return InterruptStatus;
- }
- INTERRUPT_STATUS
- DwepInterruptServiceWorker (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine processes interrupts for the DesignWare Ethernet controller at
- low level.
- Arguments:
- Parameter - Supplies an optional parameter passed in by the creator of the
- work item.
- Return Value:
- Interrupt status.
- --*/
- {
- ULONGLONG CurrentTime;
- PDWE_DEVICE Device;
- ULONG PendingBits;
- Device = (PDWE_DEVICE)(Parameter);
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Clear out the pending bits.
- //
- PendingBits = RtlAtomicExchange32(&(Device->PendingStatusBits), 0);
- if (PendingBits == 0) {
- return InterruptStatusNotClaimed;
- }
- if ((PendingBits & DWE_STATUS_RECEIVE_INTERRUPT) != 0) {
- DwepReapReceivedFrames(Device);
- }
- //
- // If the command unit finished what it was up to, reap that memory.
- //
- if ((PendingBits & DWE_STATUS_TRANSMIT_INTERRUPT) != 0) {
- DwepReapCompletedTransmitDescriptors(Device);
- }
- if ((PendingBits & DWE_STATUS_LINK_CHECK) != 0) {
- CurrentTime = KeGetRecentTimeCounter();
- Device->NextLinkCheck = CurrentTime + Device->LinkCheckInterval;
- DwepCheckLink(Device);
- }
- return InterruptStatusClaimed;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- DwepLinkCheckDpc (
- PDPC Dpc
- )
- /*++
- Routine Description:
- This routine implements the DesignWare Ethernet DPC that is queued when an
- interrupt fires.
- Arguments:
- Dpc - Supplies a pointer to the DPC that is running.
- Return Value:
- None.
- --*/
- {
- PDWE_DEVICE Device;
- ULONG OldPendingStatus;
- KSTATUS Status;
- Device = (PDWE_DEVICE)(Dpc->UserData);
- OldPendingStatus = RtlAtomicOr32(&(Device->PendingStatusBits),
- DWE_STATUS_LINK_CHECK);
- if ((OldPendingStatus & DWE_STATUS_LINK_CHECK) == 0) {
- Status = KeQueueWorkItem(Device->WorkItem);
- if (!KSUCCESS(Status)) {
- RtlAtomicAnd32(&(Device->PendingStatusBits),
- ~DWE_STATUS_LINK_CHECK);
- }
- }
- return;
- }
- KSTATUS
- DwepInitializePhy (
- PDWE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine initializes the PHY on the DesignWare Ethernet Controller.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- ULONG BasicStatus;
- ULONG PhyId;
- KSTATUS Status;
- ULONG Value;
- //
- // Find the PHY.
- //
- Device->PhyId = (ULONG)-1;
- for (PhyId = 0; PhyId < MII_PHY_COUNT; PhyId += 1) {
- BasicStatus = 0;
- Status = DwepReadMii(Device,
- PhyId,
- MiiRegisterBasicStatus,
- &BasicStatus);
- //
- // If the register presents at least one of the connection
- // possibilities, then assume its valid.
- //
- if ((KSUCCESS(Status)) && (BasicStatus != 0) &&
- (BasicStatus != MAX_USHORT) &&
- ((BasicStatus &
- (MII_BASIC_STATUS_MEDIA_MASK |
- MII_BASIC_STATUS_EXTENDED_STATUS)) != 0)) {
- Device->PhyId = PhyId;
- break;
- }
- }
- //
- // If no PHY was found, fail to start.
- //
- if (Device->PhyId == (ULONG)-1) {
- Status = STATUS_NO_SUCH_DEVICE;
- return Status;
- }
- //
- // TODO: This should be in generic MII code.
- //
- Status = DwepWriteMii(Device,
- Device->PhyId,
- MiiRegisterBasicControl,
- MII_BASIC_CONTROL_RESET);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- Value = MII_ADVERTISE_ALL | MII_ADVERTISE_CSMA | MII_ADVERTISE_PAUSE |
- MII_ADVERTISE_PAUSE_ASYMMETRIC;
- Status = DwepWriteMii(Device, Device->PhyId, MiiRegisterAdvertise, Value);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- return Status;
- }
- VOID
- DwepReadMacAddress (
- PDWE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine reads the current MAC address out of the DesignWare Ethernet
- controller.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- ULONG AddressHigh;
- ULONG AddressLow;
- if (Device->MacAddressAssigned != FALSE) {
- return;
- }
- AddressLow = DWE_READ(Device, DWE_MAC_ADDRESS_LOW(0));
- AddressHigh = DWE_READ(Device, DWE_MAC_ADDRESS_HIGH(0)) & 0x0000FFFF;
- if ((AddressLow != 0xFFFFFFFF) || (AddressHigh != 0x0000FFFF)) {
- RtlCopyMemory(Device->MacAddress, &AddressLow, sizeof(ULONG));
- RtlCopyMemory(&(Device->MacAddress[sizeof(ULONG)]),
- &AddressHigh,
- sizeof(USHORT));
- } else {
- NetCreateEthernetAddress(Device->MacAddress);
- }
- Device->MacAddressAssigned = TRUE;
- return;
- }
- VOID
- DwepReapCompletedTransmitDescriptors (
- PDWE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine cleans out any transmit descriptors completed by the hardware.
- This routine must be called at low level and assumes the command list lock
- is already held.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- UINTN Begin;
- PDWE_DESCRIPTOR Descriptor;
- BOOL DescriptorReaped;
- DescriptorReaped = FALSE;
- KeAcquireQueuedLock(Device->TransmitLock);
- while (TRUE) {
- Begin = Device->TransmitBegin;
- Descriptor = &(Device->TransmitDescriptors[Begin]);
- //
- // If the buffer size word is zeroed, that's the indication that this
- // descriptor has already been cleaned out.
- //
- if (Descriptor->BufferSize == 0) {
- break;
- }
- //
- // If the command, whatever it may be, is not complete, then this is
- // an active entry, so stop reaping.
- //
- if ((Descriptor->Control & DWE_TX_CONTROL_DMA_OWNED) != 0) {
- break;
- }
- if ((Descriptor->Control & DWE_TX_CONTROL_ERROR_MASK) != 0) {
- RtlDebugPrint("DWE: TX Error %x\n", Descriptor->Control);
- }
- //
- // Free up the packet and mark the descriptor as free for use by
- // zeroing out the control.
- //
- NetFreeBuffer(Device->TransmitPacket[Begin]);
- Device->TransmitPacket[Begin] = NULL;
- Descriptor->BufferSize = 0;
- DescriptorReaped = TRUE;
- //
- // Move the beginning of the list forward.
- //
- if (Begin == DWE_TRANSMIT_DESCRIPTOR_COUNT - 1) {
- Device->TransmitBegin = 0;
- } else {
- Device->TransmitBegin = Begin + 1;
- }
- }
- if (DescriptorReaped != FALSE) {
- DwepSendPendingPackets(Device);
- }
- KeReleaseQueuedLock(Device->TransmitLock);
- return;
- }
- VOID
- DwepSendPendingPackets (
- PDWE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine sends as many packets as can fit in the hardware descriptor
- buffer. This routine assumes the transmit lock is already held.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- PHYSICAL_ADDRESS BufferPhysical;
- ULONG Control;
- PDWE_DESCRIPTOR Descriptor;
- ULONG DescriptorIndex;
- PNET_PACKET_BUFFER Packet;
- BOOL PacketSent;
- ULONG PacketSize;
- //
- // Send as many packets as possible.
- //
- PacketSent = FALSE;
- while (NET_PACKET_LIST_EMPTY(&(Device->TransmitPacketList)) == FALSE) {
- Packet = LIST_VALUE(Device->TransmitPacketList.Head.Next,
- NET_PACKET_BUFFER,
- ListEntry);
- DescriptorIndex = Device->TransmitEnd;
- Descriptor = &(Device->TransmitDescriptors[DescriptorIndex]);
- if (Descriptor->BufferSize != 0) {
- break;
- }
- NET_REMOVE_PACKET_FROM_LIST(Packet, &(Device->TransmitPacketList));
- //
- // Success, a free descriptor. Let's fill it out!
- //
- Control = DWE_TX_CONTROL_CHAINED |
- DWE_TX_CONTROL_FIRST_SEGMENT |
- DWE_TX_CONTROL_LAST_SEGMENT |
- DWE_TX_CONTROL_INTERRUPT_ON_COMPLETE |
- DWE_TX_CONTROL_CHECKSUM_NONE |
- DWE_TX_CONTROL_DMA_OWNED;
- if ((Packet->Flags & NET_PACKET_FLAG_IP_CHECKSUM_OFFLOAD) != 0) {
- if ((Packet->Flags &
- (NET_PACKET_FLAG_TCP_CHECKSUM_OFFLOAD |
- NET_PACKET_FLAG_UDP_CHECKSUM_OFFLOAD)) != 0) {
- Control |= DWE_TX_CONTROL_CHECKSUM_PSEUDOHEADER;
- } else {
- Control |= DWE_TX_CONTROL_CHECKSUM_IP_HEADER;
- }
- }
- //
- // Fill out the transfer buffer pointer and size.
- //
- PacketSize = Packet->FooterOffset - Packet->DataOffset;
- Descriptor->BufferSize = DWE_BUFFER_SIZE(PacketSize, 0);
- BufferPhysical = Packet->BufferPhysicalAddress + Packet->DataOffset;
- ASSERT(BufferPhysical == (ULONG)BufferPhysical);
- Descriptor->Address1 = BufferPhysical;
- Device->TransmitPacket[DescriptorIndex] = Packet;
- //
- // Use a register write to write the new control value in, making
- // it live in the hardware.
- //
- HlWriteRegister32(&(Descriptor->Control), Control);
- //
- // Move the pointer past this entry.
- //
- if (DescriptorIndex == DWE_TRANSMIT_DESCRIPTOR_COUNT - 1) {
- Device->TransmitEnd = 0;
- } else {
- Device->TransmitEnd = DescriptorIndex + 1;
- }
- PacketSent = TRUE;
- }
- //
- // Write the transmit poll demand register to make the hardware take a look
- // at the transmit queue again.
- //
- if (PacketSent != FALSE) {
- DWE_WRITE(Device, DweRegisterTransmitPollDemand, 1);
- }
- return;
- }
- VOID
- DwepReapReceivedFrames (
- PDWE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine processes any received frames from the network.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- UINTN Begin;
- PDWE_DESCRIPTOR Descriptor;
- ULONG ExtendedStatus;
- NET_PACKET_BUFFER Packet;
- ULONG PayloadType;
- ULONG ReceivePhysical;
- PVOID ReceiveVirtual;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Loop grabbing completed frames.
- //
- Packet.Flags = 0;
- KeAcquireQueuedLock(Device->ReceiveLock);
- ReceivePhysical =
- (ULONG)(Device->ReceiveDataIoBuffer->Fragment[0].PhysicalAddress);
- ReceiveVirtual = Device->ReceiveDataIoBuffer->Fragment[0].VirtualAddress;
- while (TRUE) {
- Begin = Device->ReceiveBegin;
- Descriptor = &(Device->ReceiveDescriptors[Begin]);
- //
- // If the frame is not complete, then this is the end of packets that
- // need to be reaped.
- //
- if ((Descriptor->Control & DWE_RX_STATUS_DMA_OWNED) != 0) {
- break;
- }
- //
- // If the frame came through alright, send it up to the core networking
- // library to process.
- //
- if ((Descriptor->Control & DWE_RX_STATUS_ERROR_MASK) == 0) {
- Packet.Buffer = ReceiveVirtual +
- (Begin * DWE_RECEIVE_FRAME_DATA_SIZE);
- Packet.BufferPhysicalAddress =
- ReceivePhysical + (Begin * DWE_RECEIVE_FRAME_DATA_SIZE);
- Packet.BufferSize = (Descriptor->Control >>
- DWE_RX_STATUS_FRAME_LENGTH_SHIFT) &
- DWE_RX_STATUS_FRAME_LENGTH_MASK;
- Packet.DataSize = Packet.BufferSize;
- Packet.DataOffset = 0;
- Packet.FooterOffset = Packet.DataSize;
- Packet.Flags = 0;
- //
- // If receive checksum offloading is enabled, figure out how to set
- // the packet checksum offload flags.
- //
- if ((Device->ChecksumFlags &
- NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK) != 0) {
- if ((Descriptor->Control &
- DWE_RX_STATUS_EXTENDED_STATUS) != 0) {
- ExtendedStatus = Descriptor->ExtendedStatus;
- //
- // If an IP header error occurred, leave it at that.
- //
- if ((ExtendedStatus &
- DWE_RX_STATUS2_IP_HEADER_ERROR) != 0) {
- Packet.Flags |= NET_PACKET_FLAG_IP_CHECKSUM_OFFLOAD |
- NET_PACKET_FLAG_IP_CHECKSUM_FAILED;
- //
- // If the checksum was not bypassed, then the IP header
- // checksum was valid.
- //
- } else if ((ExtendedStatus &
- DWE_RX_STATUS2_IP_CHECKSUM_BYPASSED) == 0) {
- Packet.Flags |= NET_PACKET_FLAG_IP_CHECKSUM_OFFLOAD;
- PayloadType = ExtendedStatus &
- DWE_RX_STATUS2_IP_PAYLOAD_TYPE_MASK;
- //
- // Handle a TCP packet.
- //
- if (PayloadType == DWE_RX_STATUS2_IP_PAYLOAD_TCP) {
- Packet.Flags |=
- NET_PACKET_FLAG_TCP_CHECKSUM_OFFLOAD;
- if ((ExtendedStatus &
- DWE_RX_STATUS2_IP_PAYLOAD_ERROR) != 0) {
- Packet.Flags |=
- NET_PACKET_FLAG_TCP_CHECKSUM_FAILED;
- }
- //
- // Handle a UDP packet.
- //
- } else if (PayloadType ==
- DWE_RX_STATUS2_IP_PAYLOAD_UDP) {
- Packet.Flags |=
- NET_PACKET_FLAG_UDP_CHECKSUM_OFFLOAD;
- if ((ExtendedStatus &
- DWE_RX_STATUS2_IP_PAYLOAD_ERROR) != 0) {
- Packet.Flags |=
- NET_PACKET_FLAG_UDP_CHECKSUM_FAILED;
- }
- }
- }
- }
- }
- NetProcessReceivedPacket(Device->NetworkLink, &Packet);
- } else {
- RtlDebugPrint("DWE: RX Error %08x\n", Descriptor->Control);
- }
- //
- // Set this frame up to be reused, it will be the new end of the list.
- //
- HlWriteRegister32(&(Descriptor->Control), DWE_RX_STATUS_DMA_OWNED);
- //
- // Move the beginning pointer up.
- //
- if (Begin == DWE_RECEIVE_FRAME_COUNT - 1) {
- Device->ReceiveBegin = 0;
- } else {
- Device->ReceiveBegin = Begin + 1;
- }
- }
- KeReleaseQueuedLock(Device->ReceiveLock);
- return;
- }
- KSTATUS
- DwepCheckLink (
- PDWE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine checks to see if the media is connected and at what speed.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- BOOL FullDuplex;
- BOOL LinkUp;
- ULONGLONG Speed;
- KSTATUS Status;
- ULONG Value;
- Status = DwepDetermineLinkParameters(Device, &LinkUp, &Speed, &FullDuplex);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- if ((Device->LinkActive != LinkUp) ||
- (Device->LinkSpeed != Speed) ||
- (Device->FullDuplex != FullDuplex)) {
- Value = DWE_READ(Device, DweRegisterMacConfiguration);
- if (Speed == NET_SPEED_1000_MBPS) {
- Value &= ~(DWE_MAC_CONFIGURATION_RMII_SPEED_100 |
- DWE_MAC_CONFIGURATION_RMII_NOT_GIGABIT);
- } else if (Speed == NET_SPEED_100_MBPS) {
- Value |= DWE_MAC_CONFIGURATION_RMII_SPEED_100 |
- DWE_MAC_CONFIGURATION_RMII_NOT_GIGABIT;
- } else if (Speed == NET_SPEED_10_MBPS) {
- Value &= ~DWE_MAC_CONFIGURATION_RMII_SPEED_100;
- Value |= DWE_MAC_CONFIGURATION_RMII_NOT_GIGABIT;
- }
- Value &= ~DWE_MAC_CONFIGURATION_DUPLEX_MODE;
- if (FullDuplex != FALSE) {
- Value |= DWE_MAC_CONFIGURATION_DUPLEX_MODE;
- }
- DWE_WRITE(Device, DweRegisterMacConfiguration, Value);
- Device->LinkActive = LinkUp;
- Device->LinkSpeed = Speed;
- Device->FullDuplex = FullDuplex;
- NetSetLinkState(Device->NetworkLink, LinkUp, Speed);
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- DwepDetermineLinkParameters (
- PDWE_DEVICE Device,
- PBOOL LinkUp,
- PULONGLONG Speed,
- PBOOL FullDuplex
- )
- /*++
- Routine Description:
- This routine reads the link parameters out of the PHY.
- Arguments:
- Device - Supplies a pointer to the device.
- LinkUp - Supplies a pointer where a boolean will be returned indicating if
- the media is connected or not.
- Speed - Supplies a pointer where the link speed will be returned if
- connected.
- FullDuplex - Supplies a pointer where a boolean will be returned indicating
- if the connection is full duplex (TRUE) or half duplex (FALSE).
- Return Value:
- Status code.
- --*/
- {
- ULONG BasicControl;
- ULONG BasicStatus;
- ULONG BasicStatus2;
- ULONG CommonLink;
- ULONG GigabitControl;
- ULONG GigabitStatus;
- BOOL HasGigabit;
- ULONG PartnerAbility;
- KSTATUS Status;
- *LinkUp = FALSE;
- *Speed = NET_SPEED_NONE;
- *FullDuplex = FALSE;
- HasGigabit = FALSE;
- Status = DwepReadMii(Device,
- Device->PhyId,
- MiiRegisterBasicStatus,
- &BasicStatus);
- if (!KSUCCESS(Status)) {
- goto DetermineLinkParametersEnd;
- }
- Status = DwepReadMii(Device,
- Device->PhyId,
- MiiRegisterBasicStatus,
- &BasicStatus2);
- if (!KSUCCESS(Status)) {
- goto DetermineLinkParametersEnd;
- }
- BasicStatus |= BasicStatus2;
- if ((BasicStatus & MII_BASIC_STATUS_LINK_STATUS) == 0) {
- goto DetermineLinkParametersEnd;
- }
- Status = DwepReadMii(Device,
- Device->PhyId,
- MiiRegisterBasicControl,
- &BasicControl);
- if (!KSUCCESS(Status)) {
- goto DetermineLinkParametersEnd;
- }
- if ((BasicControl & MII_BASIC_CONTROL_ISOLATE) != 0) {
- goto DetermineLinkParametersEnd;
- }
- if ((BasicControl & MII_BASIC_CONTROL_LOOPBACK) != 0) {
- RtlDebugPrint("MII Loopback enabled!\n");
- }
- //
- // The link status bit is set, so media is connected. Determine what type.
- //
- *LinkUp = TRUE;
- if ((BasicControl & MII_BASIC_CONTROL_ENABLE_AUTONEGOTIATION) != 0) {
- if ((BasicStatus & MII_BASIC_STATUS_AUTONEGOTIATE_COMPLETE) == 0) {
- *LinkUp = FALSE;
- goto DetermineLinkParametersEnd;
- }
- //
- // Take the common set of the advertised abilities and the partner's
- // abilities.
- //
- Status = DwepReadMii(Device,
- Device->PhyId,
- MiiRegisterAdvertise,
- &CommonLink);
- if (!KSUCCESS(Status)) {
- goto DetermineLinkParametersEnd;
- }
- Status = DwepReadMii(Device,
- Device->PhyId,
- MiiRegisterLinkPartnerAbility,
- &PartnerAbility);
- if (!KSUCCESS(Status)) {
- goto DetermineLinkParametersEnd;
- }
- CommonLink &= PartnerAbility;
- GigabitStatus = 0;
- GigabitControl = 0;
- if (HasGigabit != FALSE) {
- Status = DwepReadMii(Device,
- Device->PhyId,
- MiiRegisterGigabitStatus,
- &GigabitStatus);
- if (!KSUCCESS(Status)) {
- goto DetermineLinkParametersEnd;
- }
- Status = DwepReadMii(Device,
- Device->PhyId,
- MiiRegisterGigabitControl,
- &GigabitControl);
- if (!KSUCCESS(Status)) {
- goto DetermineLinkParametersEnd;
- }
- }
- if (((GigabitControl & MII_GIGABIT_CONTROL_ADVERTISE_1000_FULL) != 0) &&
- ((GigabitStatus & MII_GIGABIT_STATUS_PARTNER_1000_FULL) != 0)) {
- *Speed = NET_SPEED_1000_MBPS;
- *FullDuplex = TRUE;
- } else if (((GigabitControl &
- MII_GIGABIT_CONTROL_ADVERTISE_1000_HALF) != 0) &&
- ((GigabitStatus &
- MII_GIGABIT_STATUS_PARTNER_1000_HALF) != 0)) {
- *Speed = NET_SPEED_1000_MBPS;
- *FullDuplex = TRUE;
- } else if ((CommonLink & MII_ADVERTISE_100_FULL) != 0) {
- *Speed = NET_SPEED_100_MBPS;
- *FullDuplex = TRUE;
- } else if ((CommonLink & MII_ADVERTISE_100_BASE4) != 0) {
- *Speed = NET_SPEED_100_MBPS;
- *FullDuplex = TRUE;
- } else if ((CommonLink & MII_ADVERTISE_100_HALF) != 0) {
- *Speed = NET_SPEED_100_MBPS;
- *FullDuplex = FALSE;
- } else if ((CommonLink & MII_ADVERTISE_10_FULL) != 0) {
- *Speed = NET_SPEED_10_MBPS;
- *FullDuplex = TRUE;
- } else if ((CommonLink & MII_ADVERTISE_10_HALF) != 0) {
- *Speed = NET_SPEED_10_MBPS;
- *FullDuplex = FALSE;
- } else {
- *LinkUp = FALSE;
- }
- }
- DetermineLinkParametersEnd:
- return Status;
- }
- KSTATUS
- DwepReadMii (
- PDWE_DEVICE Device,
- ULONG Phy,
- ULONG Register,
- PULONG Result
- )
- /*++
- Routine Description:
- This routine reads a register from the PHY.
- Arguments:
- Device - Supplies a pointer to the device.
- Phy - Supplies the address of the PHY.
- Register - Supplies the register to read.
- Result - Supplies a pointer where the result will be returned on success.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_DEVICE_IO_ERROR if the device could not be read.
- --*/
- {
- USHORT Mii;
- ULONGLONG Timeout;
- Mii = ((Phy & DWE_GMII_ADDRESS_DEVICE_MASK) <<
- DWE_GMII_ADDRESS_DEVICE_SHIFT) |
- ((Register & DWE_GMII_ADDRESS_REGISTER_MASK) <<
- DWE_GMII_ADDRESS_REGISTER_SHIFT) |
- (DWE_MII_CLOCK_VALUE << DWE_GMII_ADDRESS_CLOCK_RANGE_SHIFT) |
- DWE_GMII_ADDRESS_BUSY;
- DWE_WRITE(Device, DweRegisterGmiiAddress, Mii);
- Timeout = KeGetRecentTimeCounter() +
- (HlQueryTimeCounterFrequency() * DWE_MII_TIMEOUT);
- do {
- Mii = DWE_READ(Device, DweRegisterGmiiAddress);
- if ((Mii & DWE_GMII_ADDRESS_BUSY) == 0) {
- break;
- }
- KeYield();
- } while (KeGetRecentTimeCounter() <= Timeout);
- if ((Mii & DWE_GMII_ADDRESS_BUSY) != 0) {
- return STATUS_DEVICE_IO_ERROR;
- }
- *Result = DWE_READ(Device, DweRegisterGmiiData);
- return STATUS_SUCCESS;
- }
- KSTATUS
- DwepWriteMii (
- PDWE_DEVICE Device,
- ULONG Phy,
- ULONG Register,
- ULONG Value
- )
- /*++
- Routine Description:
- This routine writes a register to the PHY.
- Arguments:
- Device - Supplies a pointer to the device.
- Phy - Supplies the address of the PHY.
- Register - Supplies the register to read.
- Value - Supplies the value to write.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_DEVICE_IO_ERROR if the operation timed out.
- --*/
- {
- USHORT Mii;
- ULONGLONG Timeout;
- Mii = ((Phy & DWE_GMII_ADDRESS_DEVICE_MASK) <<
- DWE_GMII_ADDRESS_DEVICE_SHIFT) |
- ((Register & DWE_GMII_ADDRESS_REGISTER_MASK) <<
- DWE_GMII_ADDRESS_REGISTER_SHIFT) |
- (DWE_MII_CLOCK_VALUE << DWE_GMII_ADDRESS_CLOCK_RANGE_SHIFT) |
- DWE_GMII_ADDRESS_WRITE | DWE_GMII_ADDRESS_BUSY;
- DWE_WRITE(Device, DweRegisterGmiiData, Value);
- DWE_WRITE(Device, DweRegisterGmiiAddress, Mii);
- Timeout = KeGetRecentTimeCounter() +
- (HlQueryTimeCounterFrequency() * DWE_MII_TIMEOUT);
- do {
- Mii = DWE_READ(Device, DweRegisterGmiiAddress);
- if ((Mii & DWE_GMII_ADDRESS_BUSY) == 0) {
- break;
- }
- KeYield();
- } while (KeGetRecentTimeCounter() <= Timeout);
- if ((Mii & DWE_GMII_ADDRESS_BUSY) != 0) {
- return STATUS_DEVICE_IO_ERROR;
- }
- return STATUS_SUCCESS;
- }
|