1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- rtl81hw.c
- Abstract:
- This module implements device support for the Realtek RTL81xx family of
- Ethernet controllers.
- Author:
- Chris Stevens 20-Jun-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/net/netdrv.h>
- #include "rtl81.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // These checksum macros can be used to determine if the IP, UDP, or TCP
- // checksum failure bits are set in a receive descriptors command value.
- //
- #define RTL81_RECEIVE_IP_CHECKSUM_FAILURE(_Command) \
- ((_Command & RTL81_RECEIVE_DESCRIPTOR_COMMAND_IP_CHECKSUM_FAILURE) != 0)
- #define RTL81_RECEIVE_UDP_CHECKSUM_FAILURE(_Command) \
- ((_Command & RTL81_RECEIVE_DESCRIPTOR_COMMAND_UDP_CHECKSUM_FAILURE) != 0)
- #define RTL81_RECEIVE_TCP_CHECKSUM_FAILURE(_Command) \
- ((_Command & RTL81_RECEIVE_DESCRIPTOR_COMMAND_TCP_CHECKSUM_FAILURE) != 0)
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the maximum number of pending packets that will be saved before the
- // driver starts to drop packets for legacy chips. Such chips only have 4
- // descriptors, but save a fair amount of packets to be sent.
- //
- #define RTL81_MAX_TRANSMIT_PACKET_LIST_COUNT_LEGACY 64
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- Rtl81pInitializePhy (
- PRTL81_DEVICE Device
- );
- VOID
- Rtl81pCheckLinkState (
- PRTL81_DEVICE Device
- );
- VOID
- Rtl81pReapTransmitDescriptors (
- PRTL81_DEVICE Device
- );
- VOID
- Rtl81pSendPendingPackets (
- PRTL81_DEVICE Device
- );
- VOID
- Rtl81pSendPacketsLegacy (
- PRTL81_DEVICE Device
- );
- VOID
- Rtl81pSendPacketsDefault (
- PRTL81_DEVICE Device
- );
- VOID
- Rtl81pReapReceivedFrames (
- PRTL81_DEVICE Device
- );
- VOID
- Rtl81pReapReceivedFramesLegacy (
- PRTL81_DEVICE Device
- );
- VOID
- Rtl81pReapReceivedFramesDefault (
- PRTL81_DEVICE Device
- );
- KSTATUS
- Rtl81pReadMacAddress (
- PRTL81_DEVICE Device
- );
- KSTATUS
- Rtl81pReadMdio (
- PRTL81_DEVICE Device,
- RTL81_MII_REGISTER Register,
- PULONG Data
- );
- KSTATUS
- Rtl81pWriteMdio (
- PRTL81_DEVICE Device,
- RTL81_MII_REGISTER Register,
- ULONG Data
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- BOOL Rtl81DisablePacketDropping = FALSE;
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- Rtl81Send (
- 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.
- --*/
- {
- PRTL81_DEVICE Device;
- UINTN PacketListCount;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- Device = (PRTL81_DEVICE)DeviceContext;
- KeAcquireQueuedLock(Device->TransmitLock);
- //
- // 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 < Device->MaxTransmitPacketListCount) ||
- (Rtl81DisablePacketDropping != FALSE)) {
- NET_APPEND_PACKET_LIST(PacketList, &(Device->TransmitPacketList));
- Rtl81pSendPendingPackets(Device);
- Status = STATUS_SUCCESS;
- //
- // Otherwise report that the resource is use as it is too busy to handle
- // more packets.
- //
- } else {
- Status = STATUS_RESOURCE_IN_USE;
- }
- KeReleaseQueuedLock(Device->TransmitLock);
- return Status;
- }
- KSTATUS
- Rtl81GetSetInformation (
- 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;
- PRTL81_DEVICE Device;
- PULONG Flags;
- KSTATUS Status;
- USHORT Value;
- Device = (PRTL81_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 and there is not a global shut off on
- // RTL81xx devices. Requests to enable or disable receive checksum
- // offloading, however, need to modify the command 2 register.
- //
- 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. Turn it on if a flag is set and no flags were
- // previously set.
- //
- if (((*Flags & NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK) != 0) &&
- ((Device->ChecksumFlags &
- NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK) == 0)) {
- Value = RTL81_READ_REGISTER16(Device, Rtl81RegisterCommand2);
- Value |= RTL81_COMMAND_2_REGISTER_DEFAULT;
- RTL81_WRITE_REGISTER16(Device, Rtl81RegisterCommand2, Value);
- *Flags |= NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK;
- //
- // 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) &&
- ((Device->ChecksumFlags &
- NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK) != 0)) {
- Value = RTL81_READ_REGISTER16(Device, Rtl81RegisterCommand2);
- Value &= ~RTL81_COMMAND_2_REGISTER_DEFAULT;
- RTL81_WRITE_REGISTER16(Device, Rtl81RegisterCommand2, Value);
- }
- }
- //
- // Update the checksum flags.
- //
- Device->ChecksumFlags = *Flags;
- KeReleaseQueuedLock(Device->ReceiveLock);
- break;
- default:
- Status = STATUS_NOT_SUPPORTED;
- break;
- }
- return Status;
- }
- KSTATUS
- Rtl81pInitializeDeviceStructures (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine performs housekeeping preparation for resetting and enabling
- an RTL81xx device.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- UINTN AllocationSize;
- PRTL81_DEFAULT_DATA DefaultData;
- PRTL81_RECEIVE_DESCRIPTOR Descriptor;
- ULONG Flags;
- ULONG Index;
- PIO_BUFFER IoBuffer;
- ULONG IoBufferFlags;
- PHYSICAL_ADDRESS PhysicalAddress;
- ULONGLONG Size;
- KSTATUS Status;
- ULONG Version;
- ASSERT(Device->TransmitLock == NULL);
- Device->TransmitLock = KeCreateQueuedLock();
- if (Device->TransmitLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- ASSERT(Device->ReceiveLock == NULL);
- Device->ReceiveLock = KeCreateQueuedLock();
- if (Device->ReceiveLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- NET_INITIALIZE_PACKET_LIST(&(Device->TransmitPacketList));
- //
- // The range of different RTL81xx devices use various register sets and
- // descriptor modes, among other scattered properties. Determine the card
- // type now and initialize the flags.
- //
- Flags = 0;
- Version = RTL81_READ_REGISTER32(Device, Rtl81RegisterTransmitConfiguration);
- Version &= RTL81_TRANSMIT_CONFIGURATION_HARDWARE_VERSION_MASK;
- switch (Version) {
- case RTL81_HARDWARE_VERSION_8101:
- case RTL81_HARDWARE_VERSION_8130:
- case RTL81_HARDWARE_VERSION_8139:
- case RTL81_HARDWARE_VERSION_8139A:
- case RTL81_HARDWARE_VERSION_8139AG:
- case RTL81_HARDWARE_VERSION_8139B:
- case RTL81_HARDWARE_VERSION_8139C:
- Flags = RTL81_FLAG_TRANSMIT_MODE_LEGACY |
- RTL81_FLAG_REGISTER_SET_LEGACY;
- break;
- case RTL81_HARDWARE_VERSION_8139CPLUS:
- Flags = RTL81_FLAG_REGISTER_SET_LEGACY |
- RTL81_FLAG_RECEIVE_COMMAND_LEGACY |
- RTL81_FLAG_DESCRIPTOR_LIMIT_64 |
- RTL81_FLAG_MULTI_SEGMENT_SUPPORT |
- RTL81_FLAG_CHECKSUM_OFFLOAD_DEFAULT;
- break;
- case RTL81_HARDWARE_VERSION_8102EL:
- case RTL81_HARDWARE_VERSION_8168E_VL:
- Flags = RTL81_FLAG_CHECKSUM_OFFLOAD_VLAN;
- break;
- default:
- RtlDebugPrint("RTL81: Untested hardware version 0x%08x.\n", Version);
- break;
- }
- Device->Flags = Flags;
- //
- // Both checksum versions support the same features. So start with checksum
- // offloading enabled for transmit and receive.
- //
- if ((Device->Flags & RTL81_FLAG_CHECKSUM_OFFLOAD_MASK) != 0) {
- Device->ChecksumFlags = NET_LINK_CHECKSUM_FLAG_TRANSMIT_IP_OFFLOAD |
- NET_LINK_CHECKSUM_FLAG_RECEIVE_IP_OFFLOAD |
- NET_LINK_CHECKSUM_FLAG_TRANSMIT_UDP_OFFLOAD |
- NET_LINK_CHECKSUM_FLAG_RECEIVE_UDP_OFFLOAD |
- NET_LINK_CHECKSUM_FLAG_TRANSMIT_TCP_OFFLOAD |
- NET_LINK_CHECKSUM_FLAG_RECEIVE_TCP_OFFLOAD;
- }
- //
- // Set up the common transmit and receive interrupt status bits.
- //
- Device->TransmitInterruptMask = RTL81_INTERRUPT_TRANSMIT_OK |
- RTL81_INTERRUPT_TRANSMIT_ERROR;
- Device->ReceiveInterruptMask = RTL81_INTERRUPT_RECEIVE_OK |
- RTL81_INTERRUPT_RECEIVE_ERROR;
- //
- // The legacy devices have different transmit and receive data
- // requirements, so separate the initialization structures based on the
- // flags.
- //
- if ((Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0) {
- IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
- IoBuffer = MmAllocateNonPagedIoBuffer(
- 0,
- MAX_ULONG,
- RTL81_RECEIVE_RING_BUFFER_ALIGNMENT,
- RTL81_RECEIVE_RING_BUFFER_PADDED_SIZE,
- IoBufferFlags);
- if (IoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- ASSERT(IoBuffer->FragmentCount == 1);
- ASSERT(Device->U.LegacyData.ReceiveIoBuffer == NULL);
- Device->U.LegacyData.ReceiveIoBuffer = IoBuffer;
- ASSERT(Device->U.LegacyData.TransmitNextToUse == 0);
- ASSERT(Device->U.LegacyData.TransmitNextToClean == 0);
- Device->MaxTransmitPacketListCount =
- RTL81_MAX_TRANSMIT_PACKET_LIST_COUNT_LEGACY;
- } else {
- DefaultData = &(Device->U.DefaultData);
- if ((Flags & RTL81_FLAG_DESCRIPTOR_LIMIT_64) != 0) {
- DefaultData->TransmitDescriptorCount =
- RTL81_TRANSMIT_DESCRIPTOR_COUNT_LIMITED;
- DefaultData->ReceiveDescriptorCount =
- RTL81_RECEIVE_DESCRIPTOR_COUNT_LIMITED;
- } else {
- DefaultData->TransmitDescriptorCount =
- RTL81_TRANSMIT_DESCRIPTOR_COUNT_DEFAULT;
- DefaultData->ReceiveDescriptorCount =
- RTL81_RECEIVE_DESCRIPTOR_COUNT_DEFAULT;
- }
- Device->MaxTransmitPacketListCount =
- DefaultData->TransmitDescriptorCount * 2;
- AllocationSize = (DefaultData->TransmitDescriptorCount *
- sizeof(RTL81_TRANSMIT_DESCRIPTOR)) +
- (DefaultData->TransmitDescriptorCount *
- sizeof(PNET_PACKET_BUFFER)) +
- (DefaultData->ReceiveDescriptorCount *
- sizeof(RTL81_RECEIVE_DESCRIPTOR)) +
- (DefaultData->ReceiveDescriptorCount *
- RTL81_RECEIVE_BUFFER_DATA_SIZE);
- IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
- IoBuffer = MmAllocateNonPagedIoBuffer(0,
- MAX_ULONGLONG,
- RTL81_DESCRIPTOR_ALIGNMENT,
- AllocationSize,
- IoBufferFlags);
- if (IoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- ASSERT(IoBuffer->FragmentCount == 1);
- //
- // Zero out everything except the receive packet data buffers.
- //
- Size = AllocationSize -
- (DefaultData->ReceiveDescriptorCount *
- RTL81_RECEIVE_BUFFER_DATA_SIZE);
- RtlZeroMemory(IoBuffer->Fragment[0].VirtualAddress, Size);
- //
- // Carve up the buffer, giving each array its piece.
- //
- PhysicalAddress = IoBuffer->Fragment[0].PhysicalAddress;
- DefaultData->TransmitDescriptor = IoBuffer->Fragment[0].VirtualAddress;
- ASSERT(IS_ALIGNED(PhysicalAddress, RTL81_DESCRIPTOR_ALIGNMENT));
- PhysicalAddress += (DefaultData->TransmitDescriptorCount *
- sizeof(RTL81_TRANSMIT_DESCRIPTOR));
- DefaultData->TransmitBuffer =
- (PNET_PACKET_BUFFER *)(DefaultData->TransmitDescriptor +
- DefaultData->TransmitDescriptorCount);
- PhysicalAddress += (DefaultData->TransmitDescriptorCount *
- sizeof(PNET_PACKET_BUFFER));
- DefaultData->ReceiveDescriptor =
- (PRTL81_RECEIVE_DESCRIPTOR)(DefaultData->TransmitBuffer +
- DefaultData->TransmitDescriptorCount);
- ASSERT(IS_ALIGNED(PhysicalAddress, RTL81_DESCRIPTOR_ALIGNMENT));
- PhysicalAddress += (DefaultData->ReceiveDescriptorCount *
- sizeof(RTL81_RECEIVE_DESCRIPTOR));
- DefaultData->ReceivePacketData =
- (PVOID)(DefaultData->ReceiveDescriptor +
- DefaultData->ReceiveDescriptorCount);
- ASSERT(Device->U.DefaultData.DescriptorIoBuffer == NULL);
- DefaultData->DescriptorIoBuffer = IoBuffer;
- ASSERT(DefaultData->TransmitNextToUse == 0);
- ASSERT(DefaultData->TransmitNextToClean == 0);
- ASSERT(DefaultData->ReceiveNextToReap == 0);
- //
- // Initialize the receive descriptors so that they are marked as owned
- // by the hardware and have the correct physical address and size in
- // place.
- //
- ASSERT(RTL81_RECEIVE_BUFFER_DATA_SIZE <=
- (RTL81_RECEIVE_DESCRIPTOR_COMMAND_SIZE_MASK >>
- RTL81_RECEIVE_DESCRIPTOR_COMMAND_SIZE_SHIFT));
- Descriptor = NULL;
- for (Index = 0;
- Index < DefaultData->ReceiveDescriptorCount;
- Index += 1) {
- Descriptor = &(DefaultData->ReceiveDescriptor[Index]);
- Descriptor->Command = RTL81_RECEIVE_DESCRIPTOR_DEFAULT_COMMAND;
- Descriptor->PhysicalAddress = PhysicalAddress;
- PhysicalAddress += RTL81_RECEIVE_BUFFER_DATA_SIZE;
- }
- //
- // Mark the last descriptor so that the hardware knows this is the end.
- //
- Descriptor->Command |= RTL81_RECEIVE_DESCRIPTOR_COMMAND_END_OF_RING;
- //
- // Add device specific transmit and receive mask bits.
- //
- Device->TransmitInterruptMask |= RTL81_INTERRUPT_TRANSMIT_UNAVAILABLE;
- Device->ReceiveInterruptMask |= RTL81_INTERRUPT_RECEIVE_OVERFLOW;
- }
- Status = STATUS_SUCCESS;
- InitializeDeviceStructuresEnd:
- return Status;
- }
- VOID
- Rtl81pDestroyDeviceStructures (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine performs destroy any device structures allocated for the
- RTL81xx device.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- if (Device->TransmitLock != NULL) {
- KeDestroyQueuedLock(Device->TransmitLock);
- }
- if (Device->ReceiveLock != NULL) {
- KeDestroyQueuedLock(Device->ReceiveLock);
- }
- if ((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0) {
- if (Device->U.LegacyData.ReceiveIoBuffer != NULL) {
- MmFreeIoBuffer(Device->U.LegacyData.ReceiveIoBuffer);
- }
- } else {
- if (Device->U.DefaultData.DescriptorIoBuffer != NULL) {
- MmFreeIoBuffer(Device->U.DefaultData.DescriptorIoBuffer);
- }
- }
- return;
- }
- KSTATUS
- Rtl81pInitialize (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine initializes and enables the RTL81xx device.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- USHORT Command2;
- BYTE CommandRegister;
- BYTE CommandRegisterMask;
- ULONGLONG CurrentTime;
- PIO_BUFFER_FRAGMENT Fragment;
- PHYSICAL_ADDRESS PhysicalAddress;
- ULONG ReceiveBufferStart;
- ULONG ReceiveConfiguration;
- KSTATUS Status;
- ULONGLONG Timeout;
- ULONGLONG TimeoutTicks;
- TimeoutTicks = HlQueryTimeCounterFrequency() * RTL81_DEVICE_TIMEOUT;
- //
- // Execute a software reset on the devices.
- //
- RTL81_WRITE_REGISTER8(Device,
- Rtl81RegisterCommand,
- RTL81_COMMAND_REGISTER_RESET);
- CurrentTime = KeGetRecentTimeCounter();
- Timeout = CurrentTime + TimeoutTicks;
- do {
- CommandRegister = RTL81_READ_REGISTER8(Device, Rtl81RegisterCommand);
- if ((CommandRegister & RTL81_COMMAND_REGISTER_RESET) == 0) {
- break;
- }
- CurrentTime = KeGetRecentTimeCounter();
- } while (CurrentTime <= Timeout);
- if (CurrentTime > Timeout) {
- Status = STATUS_TIMEOUT;
- goto InitializeEnd;
- }
- //
- // Get the MAC address out of the EEPROM.
- //
- Status = Rtl81pReadMacAddress(Device);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Reset the PHY and start auto-negotiation.
- //
- Status = Rtl81pInitializePhy(Device);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Disable all interrupts.
- //
- RTL81_WRITE_REGISTER16(Device, Rtl81RegisterInterruptMask, 0);
- //
- // Initialize the transmit and receive buffers based on the device type.
- //
- if ((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0) {
- Fragment = &(Device->U.LegacyData.ReceiveIoBuffer->Fragment[0]);
- ASSERT(Fragment->PhysicalAddress == (ULONG)Fragment->PhysicalAddress);
- ReceiveBufferStart = (ULONG)Fragment->PhysicalAddress;;
- RTL81_WRITE_REGISTER32(Device,
- Rtl81RegisterReceiveBufferStart,
- ReceiveBufferStart);
- } else {
- //
- // Enable transmit and receive in the second command register. Also
- // enable checksum offload on receive if set.
- //
- Command2 = RTL81_COMMAND_2_REGISTER_DEFAULT;
- if ((Device->ChecksumFlags &
- NET_LINK_CHECKSUM_FLAG_RECEIVE_MASK) != 0) {
- Command2 |= RTL81_COMMAND_2_REGISTER_RECEIVE_CHECKSUM_OFFLOAD;
- }
- RTL81_WRITE_REGISTER16(Device, Rtl81RegisterCommand2, Command2);
- Fragment = &(Device->U.DefaultData.DescriptorIoBuffer->Fragment[0]);
- PhysicalAddress = Fragment->PhysicalAddress;
- RTL81_WRITE_REGISTER32(Device,
- Rtl81RegisterTransmitDescriptorBaseLow,
- (ULONG)PhysicalAddress);
- RTL81_WRITE_REGISTER32(Device,
- Rtl81RegisterTransmitDescriptorBaseHigh,
- (ULONG)(PhysicalAddress >> 32));
- PhysicalAddress += (Device->U.DefaultData.TransmitDescriptorCount *
- sizeof(RTL81_TRANSMIT_DESCRIPTOR)) +
- (Device->U.DefaultData.TransmitDescriptorCount *
- sizeof(PNET_PACKET_BUFFER));
- RTL81_WRITE_REGISTER32(Device,
- Rtl81RegisterReceiveDescriptorBaseLow,
- (ULONG)PhysicalAddress);
- RTL81_WRITE_REGISTER32(Device,
- Rtl81RegisterReceiveDescriptorBaseHigh,
- (ULONG)(PhysicalAddress >> 32));
- }
- //
- // Enable transmit and receive.
- //
- CommandRegisterMask = RTL81_COMMAND_REGISTER_RECEIVE_ENABLE |
- RTL81_COMMAND_REGISTER_TRANSMIT_ENABLE;
- RTL81_WRITE_REGISTER8(Device, Rtl81RegisterCommand, CommandRegisterMask);
- CurrentTime = KeGetRecentTimeCounter();
- Timeout = CurrentTime + TimeoutTicks;
- do {
- CommandRegister = RTL81_READ_REGISTER8(Device, Rtl81RegisterCommand);
- if ((CommandRegister & CommandRegisterMask) == CommandRegisterMask) {
- break;
- }
- CurrentTime = KeGetRecentTimeCounter();
- } while (CurrentTime <= Timeout);
- if (CurrentTime > Timeout) {
- Status = STATUS_TIMEOUT;
- goto InitializeEnd;
- }
- //
- // Configure the transmit options. This must happen after transmit has been
- // enabled.
- //
- RTL81_WRITE_REGISTER32(Device,
- Rtl81RegisterTransmitConfiguration,
- RTL81_TRANSMIT_CONFIGURATION_DEFAULT_OPTIONS);
- //
- // Configure extra transmit registers for the devices using the newer
- // register set.
- //
- if ((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) == 0) {
- RTL81_WRITE_REGISTER16(Device,
- Rtl81RegisterEarlyTransmitThreshold,
- RTL81_EARLY_TRANSMIT_THRESHOLD_DEFAULT);
- }
- //
- // Configure the receive options. This must happend after receive has been
- // enabled. Extra bits are needed for the RTL8139 chip.
- //
- ReceiveConfiguration = RTL81_RECEIVE_CONFIGURATION_DEFAULT_OPTIONS;
- if ((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0) {
- //
- // Note that the no-wrap bit has no effect when using a 64K buffer.
- //
- ReceiveConfiguration |=
- (RTL81_RECEIVE_CONFIGURATION_DEFAULT_EARLY_THRESHOLD <<
- RTL81_RECEIVE_CONFIGURATION_EARLY_TRESHOLD_SHIFT);
- }
- RTL81_WRITE_REGISTER32(Device,
- Rtl81RegisterReceiveConfiguration,
- ReceiveConfiguration);
- //
- // Configure extra receive registers for non RTL8139 devices.
- //
- if ((Device->Flags & RTL81_FLAG_REGISTER_SET_LEGACY) == 0) {
- RTL81_WRITE_REGISTER16(Device,
- Rtl81RegisterReceiveMaxPacketSize,
- RTL81_RECEIVE_BUFFER_DATA_SIZE);
- }
- //
- // Notify the networking core of this new link now that the device is ready
- // to send and receive data, pending media being present.
- //
- Status = Rtl81pAddNetworkDevice(Device);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Check to see if this link is up.
- //
- Rtl81pCheckLinkState(Device);
- //
- // Clear any pending interrupts and then enable the desired interrupts.
- //
- RTL81_WRITE_REGISTER16(Device,
- Rtl81RegisterInterruptStatus,
- RTL81_DEFAULT_INTERRUPT_MASK);
- RTL81_WRITE_REGISTER16(Device,
- Rtl81RegisterInterruptMask,
- RTL81_DEFAULT_INTERRUPT_MASK);
- Status = STATUS_SUCCESS;
- InitializeEnd:
- return Status;
- }
- INTERRUPT_STATUS
- Rtl81pInterruptService (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine implements the RTL81xx 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.
- --*/
- {
- PRTL81_DEVICE Device;
- USHORT PendingBits;
- Device = (PRTL81_DEVICE)Context;
- //
- // Read the status register, and if nothing is set then return immediately.
- //
- PendingBits = RTL81_READ_REGISTER16(Device, Rtl81RegisterInterruptStatus);
- PendingBits &= RTL81_DEFAULT_INTERRUPT_MASK;
- if (PendingBits == 0) {
- return InterruptStatusNotClaimed;
- }
- //
- // The RTL81xx devices that use MSIs require interrupts to be disabled and
- // enabled after each interrupt, otherwise the interrupts eventually stop
- // firing. That said, disable and enable the interrupts even if MSIs are
- // not in use.
- //
- RTL81_WRITE_REGISTER16(Device, Rtl81RegisterInterruptMask, 0);
- RTL81_WRITE_REGISTER16(Device, Rtl81RegisterInterruptStatus, PendingBits);
- RTL81_WRITE_REGISTER16(Device,
- Rtl81RegisterInterruptMask,
- RTL81_DEFAULT_INTERRUPT_MASK);
- RtlAtomicOr32(&(Device->PendingInterrupts), PendingBits);
- return InterruptStatusClaimed;
- }
- INTERRUPT_STATUS
- Rtl81pInterruptServiceWorker (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine processes interrupts for the RTL81xx controller at low level.
- Arguments:
- Parameter - Supplies an optional parameter passed in by the creator of the
- work item.
- Return Value:
- Interrupt status.
- --*/
- {
- PRTL81_DEVICE Device;
- ULONG PendingBits;
- Device = (PRTL81_DEVICE)(Parameter);
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Clear out the pending bits.
- //
- PendingBits = RtlAtomicExchange32(&(Device->PendingInterrupts), 0);
- if (PendingBits == 0) {
- return InterruptStatusNotClaimed;
- }
- //
- // Check to see if the link has changed.
- //
- if ((PendingBits & RTL81_INTERRUPT_LINK_CHANGE) != 0) {
- Rtl81pCheckLinkState(Device);
- }
- //
- // Communicate to the debugger if there were any receive errors.
- //
- if (((PendingBits & RTL81_INTERRUPT_RECEIVE_FIFO_OVERFLOW) != 0) ||
- ((PendingBits & RTL81_INTERRUPT_RECEIVE_ERROR) != 0) ||
- ((PendingBits & RTL81_INTERRUPT_RECEIVE_OVERFLOW) != 0)) {
- RtlDebugPrint("RTL81xx: Receive packet error 0x%x.\n", PendingBits);
- }
- //
- // If a packet was received, process it.
- //
- if ((PendingBits & Device->ReceiveInterruptMask) != 0) {
- Rtl81pReapReceivedFrames(Device);
- }
- //
- // If there was a transmit error or a successful transmit, then go through
- // and reap the packets.
- //
- if ((PendingBits & Device->TransmitInterruptMask) != 0) {
- Rtl81pReapTransmitDescriptors(Device);
- }
- return InterruptStatusClaimed;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- Rtl81pInitializePhy (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine initializes the PHY on the RTL81xx.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- USHORT BasicControl;
- ULONGLONG CurrentTime;
- KSTATUS Status;
- ULONGLONG Timeout;
- ULONGLONG TimeoutTicks;
- ULONG Value;
- TimeoutTicks = HlQueryTimeCounterFrequency() * RTL81_DEVICE_TIMEOUT;
- //
- // The RTL8139 based chips access the PHY through the basic mode registers.
- // Complete reset and auto-negotiation using those registers.
- //
- if ((Device->Flags & RTL81_FLAG_REGISTER_SET_LEGACY) != 0) {
- RTL81_WRITE_REGISTER16(Device,
- Rtl81RegisterBasicModeControl,
- RTL81_BASIC_MODE_CONTROL_INITIAL_VALUE);
- CurrentTime = KeGetRecentTimeCounter();
- Timeout = CurrentTime + TimeoutTicks;
- do {
- BasicControl = RTL81_READ_REGISTER16(Device,
- Rtl81RegisterBasicModeControl);
- if ((BasicControl & RTL81_BASIC_MODE_CONTROL_RESET) == 0) {
- break;
- }
- CurrentTime = KeGetRecentTimeCounter();
- } while (CurrentTime <= Timeout);
- if (CurrentTime > Timeout) {
- Status = STATUS_TIMEOUT;
- goto InitializePhyEnd;
- }
- //
- // RTL8168 and above access the PHY through the MII registers. Reset the
- // PHY and then start auto-negotiation.
- //
- } else {
- Status = Rtl81pWriteMdio(Device,
- Rtl81MiiRegisterBasicControl,
- RTL81_MII_BASIC_CONTROL_RESET);
- if (!KSUCCESS(Status)) {
- goto InitializePhyEnd;
- }
- CurrentTime = KeGetRecentTimeCounter();
- Timeout = CurrentTime + TimeoutTicks;
- do {
- Status = Rtl81pReadMdio(Device,
- Rtl81MiiRegisterBasicControl,
- &Value);
- if (!KSUCCESS(Status)) {
- goto InitializePhyEnd;
- }
- BasicControl = (USHORT)Value;
- if ((BasicControl & RTL81_MII_BASIC_CONTROL_RESET) == 0) {
- break;
- }
- CurrentTime = KeGetRecentTimeCounter();
- } while (CurrentTime <= Timeout);
- if (CurrentTime > Timeout) {
- Status = STATUS_TIMEOUT;
- goto InitializePhyEnd;
- }
- Status = Rtl81pWriteMdio(Device,
- Rtl81MiiRegisterAdvertise,
- RTL81_MII_ADVERTISE_ALL);
- if (!KSUCCESS(Status)) {
- goto InitializePhyEnd;
- }
- //
- // The gigabit control register needs to be read, modified, and
- // written as not all bits are advertisement related.
- //
- Status = Rtl81pReadMdio(Device, Rtl81MiiRegisterGigabitControl, &Value);
- if (!KSUCCESS(Status)) {
- goto InitializePhyEnd;
- }
- Value |= (RTL81_MII_GIGABIT_CONTROL_ADVERTISE_1000_FULL |
- RTL81_MII_GIGABIT_CONTROL_ADVERTISE_1000_HALF);
- Status = Rtl81pWriteMdio(Device, Rtl81MiiRegisterGigabitControl, Value);
- if (!KSUCCESS(Status)) {
- goto InitializePhyEnd;
- }
- Value = RTL81_MII_BASIC_CONTROL_ENABLE_AUTONEGOTIATION |
- RTL81_MII_BASIC_CONTROL_RESTART_AUTONEGOTIATION;
- Status = Rtl81pWriteMdio(Device, Rtl81MiiRegisterBasicControl, Value);
- if (!KSUCCESS(Status)) {
- goto InitializePhyEnd;
- }
- }
- Status = STATUS_SUCCESS;
- InitializePhyEnd:
- return Status;
- }
- VOID
- Rtl81pCheckLinkState (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine checks the state of the link and will notify the networking
- core if the link is up or down.
- Arguments:
- Device - Supplies a pointer to the RTL81xx device.
- Return Value:
- None.
- --*/
- {
- ULONGLONG LinkSpeed;
- BYTE MediaStatus;
- BYTE PhyStatus;
- //
- // The RTL8139 based devices use the media status register.
- //
- if ((Device->Flags & RTL81_FLAG_REGISTER_SET_LEGACY) != 0) {
- MediaStatus = RTL81_READ_REGISTER8(Device, Rtl81RegisterMediaStatus);
- if ((MediaStatus & RTL81_MEDIA_STATUS_SPEED_10) != 0) {
- LinkSpeed = NET_SPEED_10_MBPS;
- } else {
- LinkSpeed = NET_SPEED_100_MBPS;
- }
- if ((MediaStatus & RTL81_MEDIA_STATUS_LINK_DOWN) == 0) {
- NetSetLinkState(Device->NetworkLink, TRUE, LinkSpeed);
- } else {
- NetSetLinkState(Device->NetworkLink, FALSE, LinkSpeed);
- }
- //
- // Otherwise the PHY status register is used.
- //
- } else {
- PhyStatus = RTL81_READ_REGISTER8(Device, Rtl81RegisterPhyStatus);
- if ((PhyStatus & RTL81_PHY_STATUS_SPEED_10) != 0) {
- LinkSpeed = NET_SPEED_10_MBPS;
- } else if ((PhyStatus & RTL81_PHY_STATUS_SPEED_100) != 0) {
- LinkSpeed = NET_SPEED_100_MBPS;
- } else if ((PhyStatus & RTL81_PHY_STATUS_SPEED_1000) != 0) {
- LinkSpeed = NET_SPEED_1000_MBPS;
- } else {
- ASSERT((PhyStatus & RTL81_PHY_STATUS_LINK_UP) == 0);
- LinkSpeed = 0;
- }
- if ((PhyStatus & RTL81_PHY_STATUS_LINK_UP) != 0) {
- NetSetLinkState(Device->NetworkLink, TRUE, LinkSpeed);
- } else {
- NetSetLinkState(Device->NetworkLink, FALSE, LinkSpeed);
- }
- }
- return;
- }
- VOID
- Rtl81pReapTransmitDescriptors (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine attempts to reap any transmit descriptors that completed or
- experienced an error. It will send along more data if it released any
- descriptors.
- Arguments:
- Device - Supplies a pointer to the RTL81xx device.
- Return Value:
- None.
- --*/
- {
- ULONG Command;
- PRTL81_DEFAULT_DATA DefaultData;
- PRTL81_TRANSMIT_DESCRIPTOR Descriptor;
- BOOL DescriptorReaped;
- LIST_ENTRY DestroyList;
- PRTL81_LEGACY_DATA LegacyData;
- USHORT NextToClean;
- PNET_PACKET_BUFFER Packet;
- RTL81_REGISTER Register;
- ULONG TransmitStatus;
- DescriptorReaped = FALSE;
- INITIALIZE_LIST_HEAD(&DestroyList);
- KeAcquireQueuedLock(Device->TransmitLock);
- //
- // Check all descriptors between the next to clean and the next to use. If
- // the two values are equal and an interrupt came in, it likely means that
- // all descriptors are eligble for reaping, rather than none. Split this
- // logic based on the device type.
- //
- if ((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0) {
- LegacyData = &(Device->U.LegacyData);
- do {
- NextToClean = LegacyData->TransmitNextToClean;
- //
- // If the next descriptor to clean is not in use, then skip
- // cleaning entirely.
- //
- if (LegacyData->ActiveTransmitPackets[NextToClean] == NULL) {
- break;
- }
- Register = Rtl81RegisterTransmitStatus0 +
- (NextToClean * sizeof(ULONG));
- TransmitStatus = RTL81_READ_REGISTER32(Device, Register);
- //
- // If the transmission was not aborted, completed or underrun, then
- // the descriptor cannot be reaped. Break out of the loop as the
- // descriptors are serviced in round-robin style.
- //
- if (((TransmitStatus & RTL81_TRANSMIT_STATUS_ABORT) == 0) &&
- ((TransmitStatus & RTL81_TRANSMIT_STATUS_OK) == 0) &&
- ((TransmitStatus & RTL81_TRANSMIT_STATUS_FIFO_UNDERRUN) == 0)) {
- break;
- }
- DescriptorReaped = TRUE;
- Packet = LegacyData->ActiveTransmitPackets[NextToClean];
- INSERT_BEFORE(&(Packet->ListEntry), &DestroyList);
- LegacyData->ActiveTransmitPackets[NextToClean] = NULL;
- //
- // Advance to clean the next descriptor.
- //
- LegacyData->TransmitNextToClean += 1;
- if (LegacyData->TransmitNextToClean ==
- RTL81_TRANSMIT_DESCRIPTOR_COUNT_LEGACY) {
- LegacyData->TransmitNextToClean = 0;
- }
- } while (LegacyData->TransmitNextToClean !=
- LegacyData->TransmitNextToUse);
- } else {
- DefaultData = &(Device->U.DefaultData);
- do {
- NextToClean = DefaultData->TransmitNextToClean;
- //
- // If the next descriptor to clean is not in use, then skip
- // cleaning entirely.
- //
- if (DefaultData->TransmitBuffer[NextToClean] == NULL) {
- break;
- }
- Descriptor = &(DefaultData->TransmitDescriptor[NextToClean]);
- Command = Descriptor->Command;
- //
- // If the hardware still owns the descriptor, then it cannot be
- // reclaimed. Skip the rest of the cleaning.
- //
- if ((Command & RTL81_TRANSMIT_DESCRIPTOR_COMMAND_OWN) != 0) {
- break;
- }
- DescriptorReaped = TRUE;
- Packet = DefaultData->TransmitBuffer[NextToClean];
- INSERT_BEFORE(&(Packet->ListEntry), &DestroyList);
- DefaultData->TransmitBuffer[NextToClean] = NULL;
- //
- // Advance to clean the next descriptor.
- //
- DefaultData->TransmitNextToClean += 1;
- if (DefaultData->TransmitNextToClean ==
- DefaultData->TransmitDescriptorCount) {
- DefaultData->TransmitNextToClean = 0;
- }
- } while (DefaultData->TransmitNextToClean !=
- DefaultData->TransmitNextToUse);
- //
- // If there are still packets waiting to be sent, then flush them
- // through in case the hardware went idle.
- //
- if (DefaultData->TransmitNextToClean !=
- DefaultData->TransmitNextToUse) {
- if ((Device->Flags & RTL81_FLAG_REGISTER_SET_LEGACY) != 0) {
- RTL81_WRITE_REGISTER8(Device,
- Rtl81RegisterTransmitPriorityPolling2,
- RTL81_TRANSMIT_PRIORITY_POLLING_NORMAL);
- } else {
- RTL81_WRITE_REGISTER8(Device,
- Rtl81RegisterTransmitPriorityPolling1,
- RTL81_TRANSMIT_PRIORITY_POLLING_NORMAL);
- }
- }
- }
- //
- // If a descriptor was reaped, then try to pump more packets through.
- //
- if (DescriptorReaped != FALSE) {
- Rtl81pSendPendingPackets(Device);
- }
- KeReleaseQueuedLock(Device->TransmitLock);
- //
- // Destroy any reaped buffers.
- //
- while (LIST_EMPTY(&DestroyList) == FALSE) {
- Packet = LIST_VALUE(DestroyList.Next, NET_PACKET_BUFFER, ListEntry);
- LIST_REMOVE(&(Packet->ListEntry));
- NetFreeBuffer(Packet);
- }
- return;
- }
- VOID
- Rtl81pSendPendingPackets (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine sends any pending packets as long as there are free
- descriptors available. This routine assumes that the device's lock is held.
- Arguments:
- Device - Supplies a pointer to the RTL81xx device.
- Return Value:
- None.
- --*/
- {
- if ((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0) {
- Rtl81pSendPacketsLegacy(Device);
- } else {
- Rtl81pSendPacketsDefault(Device);
- }
- return;
- }
- VOID
- Rtl81pSendPacketsLegacy (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine sends any pending packets for a legacy transmit device as long
- as there are free descriptors available. This routine assumes that the
- device's lock is held.
- Arguments:
- Device - Supplies a pointer to the RTL81xx device.
- Return Value:
- None.
- --*/
- {
- PRTL81_LEGACY_DATA LegacyData;
- USHORT NextToUse;
- ULONG Offset;
- PNET_PACKET_BUFFER Packet;
- PHYSICAL_ADDRESS PhysicalAddress;
- ULONG Size;
- ASSERT(KeIsQueuedLockHeld(Device->TransmitLock) != FALSE);
- ASSERT((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0);
- //
- // Iterate over the list of pending transmit packets allocating them to
- // free descriptors, if there are any.
- //
- LegacyData = &(Device->U.LegacyData);
- while (NET_PACKET_LIST_EMPTY(&(Device->TransmitPacketList)) == FALSE) {
- //
- // Get the next descriptor to use. If it is not available, then
- // exit. Otherwise increment the next to use index.
- //
- NextToUse = LegacyData->TransmitNextToUse;
- if (LegacyData->ActiveTransmitPackets[NextToUse] != NULL) {
- break;
- }
- LegacyData->TransmitNextToUse += 1;
- if (LegacyData->TransmitNextToUse ==
- RTL81_TRANSMIT_DESCRIPTOR_COUNT_LEGACY) {
- LegacyData->TransmitNextToUse = 0;
- }
- Packet = LIST_VALUE(Device->TransmitPacketList.Head.Next,
- NET_PACKET_BUFFER,
- ListEntry);
- NET_REMOVE_PACKET_FROM_LIST(Packet, &(Device->TransmitPacketList));
- //
- // Remember the packet so that it can be released once it is
- // successfully sent and then begin the transmit process. Setting
- // the size in the status register also sets the OWN bit to 0,
- // triggering the start of the transmission. Thus, the physical
- // address must be programmed first.
- //
- ASSERT(LegacyData->ActiveTransmitPackets[NextToUse] == NULL);
- LegacyData->ActiveTransmitPackets[NextToUse] = Packet;
- Offset = NextToUse * sizeof(ULONG);
- PhysicalAddress = Packet->BufferPhysicalAddress + Packet->DataOffset;
- ASSERT(PhysicalAddress == (ULONG)PhysicalAddress);
- RTL81_WRITE_REGISTER32(Device,
- (Rtl81RegisterTransmitAddress0 + Offset),
- (ULONG)PhysicalAddress);
- Size = Packet->FooterOffset - Packet->DataOffset;
- ASSERT(Size <= RTL81_MAX_TRANSMIT_PACKET_SIZE);
- //
- // The RTL8139C does not automatically pad runt packets (less than
- // 64 bytes). The buffer should have been zero'd as this driver
- // registered a minimum packet length with net core. Adjust the size,
- // leaving space for the hardware to fill in the CRC.
- //
- if (Size < (RTL81_MINIMUM_PACKET_LENGTH - sizeof(ULONG))) {
- ASSERT(Packet->BufferSize >= RTL81_MINIMUM_PACKET_LENGTH);
- Size = RTL81_MINIMUM_PACKET_LENGTH - sizeof(ULONG);
- }
- RTL81_WRITE_REGISTER32(Device,
- (Rtl81RegisterTransmitStatus0 + Offset),
- Size);
- }
- return;
- }
- VOID
- Rtl81pSendPacketsDefault (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine sends any pending packets for a default transmit device as
- long as there are free descriptors available. This routine assumes that the
- device's lock is held.
- Arguments:
- Device - Supplies a pointer to the RTL81xx device.
- Return Value:
- None.
- --*/
- {
- ULONG Command;
- PRTL81_DEFAULT_DATA DefaultData;
- PRTL81_TRANSMIT_DESCRIPTOR Descriptor;
- ULONG Flags;
- USHORT NextToUse;
- PNET_PACKET_BUFFER Packet;
- BOOL PacketSubmitted;
- PHYSICAL_ADDRESS PhysicalAddress;
- ULONG Size;
- ULONG VlanTag;
- ASSERT(KeIsQueuedLockHeld(Device->TransmitLock) != FALSE);
- ASSERT((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) == 0);
- //
- // Iterate over the list of pending transmit packets allocating them to
- // free descriptors, if there are any.
- //
- DefaultData = &(Device->U.DefaultData);
- PacketSubmitted = FALSE;
- while (NET_PACKET_LIST_EMPTY(&(Device->TransmitPacketList)) == FALSE) {
- //
- // Get the next descriptor to use. If it is not available, then
- // exit. Otherwise increment the next to use index.
- //
- NextToUse = DefaultData->TransmitNextToUse;
- if (DefaultData->TransmitBuffer[NextToUse] != NULL) {
- break;
- }
- DefaultData->TransmitNextToUse += 1;
- if (DefaultData->TransmitNextToUse ==
- DefaultData->TransmitDescriptorCount) {
- DefaultData->TransmitNextToUse = 0;
- }
- Packet = LIST_VALUE(Device->TransmitPacketList.Head.Next,
- NET_PACKET_BUFFER,
- ListEntry);
- NET_REMOVE_PACKET_FROM_LIST(Packet, &(Device->TransmitPacketList));
- //
- // Remember the packet so that it can be released once it is
- // successfully sent and then begin the transmit process.
- //
- ASSERT(DefaultData->TransmitBuffer[NextToUse] == NULL);
- DefaultData->TransmitBuffer[NextToUse] = Packet;
- //
- // Program the descriptor with the packets data.
- //
- Size = Packet->FooterOffset - Packet->DataOffset;
- ASSERT(Size <= RTL81_MAX_TRANSMIT_PACKET_SIZE);
- Command = RTL81_TRANSMIT_DESCRIPTOR_COMMAND_OWN |
- RTL81_TRANSMIT_DESCRIPTOR_COMMAND_FIRST_SEGMENT |
- RTL81_TRANSMIT_DESCRIPTOR_COMMAND_LAST_SEGMENT |
- ((Size << RTL81_TRANSMIT_DESCRIPTOR_COMMAND_SIZE_SHIFT) &
- RTL81_TRANSMIT_DESCRIPTOR_COMMAND_SIZE_MASK);
- //
- // See if any checksum offloads were requested.
- //
- VlanTag = 0;
- if ((Device->Flags & RTL81_FLAG_CHECKSUM_OFFLOAD_DEFAULT) != 0) {
- Flags = Packet->Flags;
- if ((Flags & NET_PACKET_FLAG_IP_CHECKSUM_OFFLOAD) != 0) {
- Command |=
- RTL81_TRANSMIT_DESCRIPTOR_COMMAND_IP_CHECKSUM_OFFLOAD;
- }
- if ((Flags & NET_PACKET_FLAG_UDP_CHECKSUM_OFFLOAD) != 0) {
- Command |=
- RTL81_TRANSMIT_DESCRIPTOR_COMMAND_UDP_CHECKSUM_OFFLOAD;
- } else if ((Flags & NET_PACKET_FLAG_TCP_CHECKSUM_OFFLOAD) != 0) {
- Command |=
- RTL81_TRANSMIT_DESCRIPTOR_COMMAND_TCP_CHECKSUM_OFFLOAD;
- }
- } else if ((Device->Flags & RTL81_FLAG_CHECKSUM_OFFLOAD_VLAN) != 0) {
- Flags = Packet->Flags;
- if ((Flags & NET_PACKET_FLAG_IP_CHECKSUM_OFFLOAD) != 0) {
- VlanTag |= RTL81_TRANSMIT_DESCRIPTOR_VLAN_IP_CHECKSUM_OFFLOAD;
- }
- if ((Flags & NET_PACKET_FLAG_UDP_CHECKSUM_OFFLOAD) != 0) {
- VlanTag |= RTL81_TRANSMIT_DESCRIPTOR_VLAN_UDP_CHECKSUM_OFFLOAD;
- } else if ((Flags & NET_PACKET_FLAG_TCP_CHECKSUM_OFFLOAD) != 0) {
- VlanTag |= RTL81_TRANSMIT_DESCRIPTOR_VLAN_TCP_CHECKSUM_OFFLOAD;
- }
- }
- if (NextToUse == (DefaultData->TransmitDescriptorCount - 1)) {
- Command |= RTL81_TRANSMIT_DESCRIPTOR_COMMAND_END_OF_RING;
- }
- PhysicalAddress = Packet->BufferPhysicalAddress +
- Packet->DataOffset;
- Descriptor = &(DefaultData->TransmitDescriptor[NextToUse]);
- Descriptor->VlanTag = VlanTag;
- Descriptor->PhysicalAddress = PhysicalAddress;
- RtlMemoryBarrier();
- Descriptor->Command = Command;
- PacketSubmitted = TRUE;
- }
- //
- // If a packet was submitted by setting its state in a descriptor, then
- // poke the hardware to let it know to check the transmit queue.
- //
- if (PacketSubmitted != FALSE) {
- if ((Device->Flags & RTL81_FLAG_REGISTER_SET_LEGACY) != 0) {
- RTL81_WRITE_REGISTER8(Device,
- Rtl81RegisterTransmitPriorityPolling2,
- RTL81_TRANSMIT_PRIORITY_POLLING_NORMAL);
- } else {
- RTL81_WRITE_REGISTER8(Device,
- Rtl81RegisterTransmitPriorityPolling1,
- RTL81_TRANSMIT_PRIORITY_POLLING_NORMAL);
- }
- }
- return;
- }
- VOID
- Rtl81pReapReceivedFrames (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine reaps received frames from RTL81xx hardware and notifies the
- core networking driver about a packet's arrival.
- Arguments:
- Device - Supplies a pointer to the RTL81xx device.
- Return Value:
- None.
- --*/
- {
- KeAcquireQueuedLock(Device->ReceiveLock);
- //
- // Handle the reaping based on the device type. RTL8139 is different than
- // everything else.
- //
- if ((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0) {
- Rtl81pReapReceivedFramesLegacy(Device);
- } else {
- Rtl81pReapReceivedFramesDefault(Device);
- }
- KeReleaseQueuedLock(Device->ReceiveLock);
- return;
- }
- VOID
- Rtl81pReapReceivedFramesLegacy (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine reaps received frames from the legacy RTL receive ring buffer
- and notifies the core networking driver about a packet's arrival.
- Arguments:
- Device - Supplies a pointer to the RTL81xx device.
- Return Value:
- None.
- --*/
- {
- USHORT AlignedOffset;
- USHORT BytesReaped;
- BYTE CommandRegister;
- USHORT CurrentOffset;
- BYTE EarlyStatus;
- USHORT EndOffset;
- PIO_BUFFER_FRAGMENT Fragment;
- PRTL81_PACKET_HEADER Header;
- PRTL81_LEGACY_DATA LegacyData;
- USHORT MaxBytesToReap;
- NET_PACKET_BUFFER Packet;
- USHORT PacketLength;
- PHYSICAL_ADDRESS PhysicalAddress;
- USHORT ReadPacketAddress;
- PVOID VirtualAddress;
- USHORT WrapLength;
- USHORT WrapOffset;
- ASSERT((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0);
- LegacyData = &(Device->U.LegacyData);
- Packet.IoBuffer = NULL;
- Packet.ListEntry.Next = NULL;
- Packet.Flags = 0;
- //
- // Get the current read offset and the hardware's write offset.
- //
- CurrentOffset = RTL81_READ_REGISTER16(Device,
- Rtl81RegisterReadPacketAddress);
- CurrentOffset += RTL81_RECEIVE_OFFSET_ADJUSTMENT;
- if (CurrentOffset >= RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET) {
- CurrentOffset -= RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET;
- }
- EndOffset = RTL81_READ_REGISTER16(Device,
- Rtl81RegisterReceiveBufferCurrent);
- ASSERT(EndOffset < RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET);
- //
- // Figure how many good bytes are available to process, accounting for
- // the wrap around.
- //
- if (EndOffset > CurrentOffset) {
- MaxBytesToReap = EndOffset - CurrentOffset;
- } else {
- MaxBytesToReap = (RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET -
- CurrentOffset) +
- EndOffset;
- }
- Fragment = &(LegacyData->ReceiveIoBuffer->Fragment[0]);
- VirtualAddress = Fragment->VirtualAddress;
- PhysicalAddress = Fragment->PhysicalAddress;
- //
- // Loop until the buffer is empty according to the command register or
- // until the maximum bytes have been reaped.
- //
- BytesReaped = 0;
- CommandRegister = RTL81_READ_REGISTER8(Device, Rtl81RegisterCommand);
- while ((CommandRegister & RTL81_COMMAND_REGISTER_BUFFER_EMPTY) == 0) {
- Header = (PRTL81_PACKET_HEADER)(VirtualAddress + CurrentOffset);
- //
- // If the packet is early or there was an error, break out of the loop.
- //
- if (((Header->Status & RTL81_RECEIVE_PACKET_STATUS_OK) == 0) ||
- ((Header->Status & RTL81_RECEIVE_PACKET_ERROR_MASK) != 0) ||
- (Header->Length > RTL81_MAXIMUM_PACKET_LENGTH) ||
- (Header->Length < RTL81_MINIMUM_PACKET_LENGTH)) {
- EarlyStatus = RTL81_READ_REGISTER8(Device,
- Rtl81RegisterEarlyReceiveStatus);
- if ((EarlyStatus & RTL81_EARLY_RECEIVE_STATUS_OK) != 0) {
- break;
- }
- CommandRegister = RTL81_READ_REGISTER8(Device,
- Rtl81RegisterCommand);
- CommandRegister &= ~RTL81_COMMAND_REGISTER_RECEIVE_ENABLE;
- RTL81_WRITE_REGISTER8(Device,
- Rtl81RegisterCommand,
- CommandRegister);
- CommandRegister |= RTL81_COMMAND_REGISTER_RECEIVE_ENABLE;
- RTL81_WRITE_REGISTER8(Device,
- Rtl81RegisterCommand,
- CommandRegister);
- RTL81_WRITE_REGISTER32(Device,
- Rtl81RegisterReceiveConfiguration,
- RTL81_RECEIVE_CONFIGURATION_DEFAULT_OPTIONS);
- ReadPacketAddress = RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET -
- RTL81_RECEIVE_OFFSET_ADJUSTMENT;
- RTL81_WRITE_REGISTER16(Device,
- Rtl81RegisterReadPacketAddress,
- ReadPacketAddress);
- break;
- }
- //
- // The header indicated a valid packet, try to count these as reaped
- // bytes. If these bytes extend beyond the pre-calculated total, exit
- // the loop now, they packet likely isn't ready.
- //
- BytesReaped += sizeof(RTL81_PACKET_HEADER) + Header->Length;
- if (BytesReaped > MaxBytesToReap) {
- break;
- }
- //
- // Create a network buffer packet to send to the networking core. Get
- // the offset of the actual data by skipping over the header. Wrap
- // around to zero if the current offset went beyond the end.
- //
- CurrentOffset += sizeof(RTL81_PACKET_HEADER);
- if (CurrentOffset >= RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET) {
- CurrentOffset -= RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET;
- }
- //
- // Remove the size of the CRC from the length.
- //
- PacketLength = Header->Length - RTL81_RECEIVE_CRC_LENGTH;
- //
- // Extra space was left at the end of the receive I/O buffer to handle
- // wrapping, so copy any wrapped data to the end of the buffer. Move
- // the current offset forward, accounting for the CRC.
- //
- ASSERT(CurrentOffset < RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET);
- Packet.Buffer = VirtualAddress + CurrentOffset;
- Packet.BufferPhysicalAddress = PhysicalAddress + CurrentOffset;
- WrapOffset = RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET - CurrentOffset;
- if (PacketLength > WrapOffset) {
- WrapLength = PacketLength - WrapOffset;
- RtlCopyMemory(Packet.Buffer + WrapOffset,
- VirtualAddress,
- WrapLength);
- CurrentOffset = WrapLength + RTL81_RECEIVE_CRC_LENGTH;
- } else {
- CurrentOffset += PacketLength + RTL81_RECEIVE_CRC_LENGTH;
- }
- if (CurrentOffset >= RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET) {
- CurrentOffset -= RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET;
- }
- //
- // Remove the size of the CRC from the length.
- //
- Packet.BufferSize = PacketLength;
- Packet.DataSize = PacketLength;
- Packet.DataOffset = 0;
- Packet.FooterOffset = PacketLength;
- NetProcessReceivedPacket(Device->NetworkLink, &Packet);
- //
- // Move past this packet. The current offset is set to the end of the
- // CRC. Just align it up and then notify the hardware. Count these as
- // bytes reaped.
- //
- AlignedOffset = ALIGN_RANGE_UP(CurrentOffset,
- RTL81_RECEIVE_RING_BUFFER_ALIGNMENT);
- if (AlignedOffset >= RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET) {
- AlignedOffset = 0;
- BytesReaped += RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET -
- CurrentOffset;
- } else {
- BytesReaped += AlignedOffset - CurrentOffset;
- }
- CurrentOffset = AlignedOffset;
- if (CurrentOffset >= RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET) {
- CurrentOffset -= RTL81_MAXIMUM_RECEIVE_RING_BUFFER_OFFSET;
- }
- //
- // Don't update the current offset with the adjustment as the next
- // packet should be sitting at the offset before the adjustment.
- //
- ReadPacketAddress = CurrentOffset - RTL81_RECEIVE_OFFSET_ADJUSTMENT;
- RTL81_WRITE_REGISTER16(Device,
- Rtl81RegisterReadPacketAddress,
- ReadPacketAddress);
- //
- // Update the command register status now that a packet has been
- // processed. The buffer may be empty.
- //
- CommandRegister = RTL81_READ_REGISTER8(Device, Rtl81RegisterCommand);
- }
- return;
- }
- VOID
- Rtl81pReapReceivedFramesDefault (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine reaps received frames from receive descriptors of the newer
- RTL8139C+, RTL8168, and similar chips. It then notifies the core networking
- driver about a packet's arrival.
- Arguments:
- Device - Supplies a pointer to the RTL81xx device.
- Return Value:
- None.
- --*/
- {
- ULONG Command;
- PRTL81_DEFAULT_DATA DefaultData;
- PRTL81_RECEIVE_DESCRIPTOR Descriptor;
- ULONG Flags;
- USHORT NextToReap;
- NET_PACKET_BUFFER Packet;
- ULONG Protocol;
- ULONG SegmentFlags;
- ULONG Size;
- ULONG VlanTag;
- ASSERT((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) == 0);
- Packet.IoBuffer = NULL;
- Packet.ListEntry.Next = NULL;
- Descriptor = NULL;
- DefaultData = &(Device->U.DefaultData);
- SegmentFlags = RTL81_RECEIVE_DESCRIPTOR_COMMAND_FIRST_SEGMENT |
- RTL81_RECEIVE_DESCRIPTOR_COMMAND_LAST_SEGMENT;
- while (TRUE) {
- //
- // If this isn't the first time around, advance the next to index and
- // reset the current descriptor.
- //
- if (Descriptor != NULL) {
- Command = RTL81_RECEIVE_DESCRIPTOR_DEFAULT_COMMAND;
- DefaultData->ReceiveNextToReap += 1;
- if (DefaultData->ReceiveNextToReap ==
- DefaultData->ReceiveDescriptorCount) {
- Command |= RTL81_RECEIVE_DESCRIPTOR_COMMAND_END_OF_RING;
- DefaultData->ReceiveNextToReap = 0;
- }
- Descriptor->Command = Command;
- }
- //
- // Try to harvest the packet in te next descriptor.
- //
- NextToReap = DefaultData->ReceiveNextToReap;
- Descriptor = &(DefaultData->ReceiveDescriptor[NextToReap]);
- //
- // If the descriptor is still in use by the hardware, then stop.
- //
- Command = Descriptor->Command;
- if ((Command & RTL81_RECEIVE_DESCRIPTOR_COMMAND_OWN) != 0) {
- break;
- }
- //
- // Rtl8168C and above do not support multi-segment packets. Discard
- // such packets.
- //
- if (((Device->Flags & RTL81_FLAG_MULTI_SEGMENT_SUPPORT) == 0) &&
- ((Command & SegmentFlags) != SegmentFlags)) {
- continue;
- }
- //
- // This is a valid packet that needs to be reaped. Only single
- // packets are supported.
- //
- ASSERT((Command & SegmentFlags) == SegmentFlags);
- //
- // The command bits differ between the RTL8139C+ and newer chips.
- // Handle that now.
- //
- if ((Device->Flags & RTL81_FLAG_RECEIVE_COMMAND_LEGACY) != 0) {
- Size = (Command & RTL81_RECEIVE_DESCRIPTOR_COMMAND_SIZE_MASK) >>
- RTL81_RECEIVE_DESCRIPTOR_COMMAND_SIZE_SHIFT;
- } else {
- Size = (Command &
- RTL81_RECEIVE_DESCRIPTOR_COMMAND_LARGE_SIZE_MASK) >>
- RTL81_RECEIVE_DESCRIPTOR_COMMAND_LARGE_SIZE_SHIFT;
- //
- // With the size and top four bits out of the way, modify the
- // command variable so that the values match those of the older
- // model.
- //
- Command >>= RTL81_RECEIVE_DESCRIPTOR_COMMAND_SHIFT;
- }
- //
- // Skip the packet if any error flags are set.
- //
- if ((Command & RTL81_RECEIVE_DESCRIPTOR_COMMAND_ERROR_SUMMARY) != 0) {
- continue;
- }
- //
- // Collect the checksum flags, passing the packet to the networking
- // core even if the checksum failed.
- //
- Flags = 0;
- Protocol = (Command & RTL81_RECEIVE_DESCRIPTOR_COMMAND_PROTOCOL_MASK) >>
- RTL81_RECEIVE_DESCRIPTOR_COMMAND_PROTOCOL_SHIFT;
- if (Protocol != 0) {
- VlanTag = Descriptor->VlanTag;
- if (((Device->Flags & RTL81_FLAG_CHECKSUM_OFFLOAD_VLAN) == 0) ||
- ((VlanTag & RTL81_RECEIVE_DESCRIPTOR_VLAN_IP4) != 0)) {
- Flags |= NET_PACKET_FLAG_IP_CHECKSUM_OFFLOAD;
- if (RTL81_RECEIVE_IP_CHECKSUM_FAILURE(Command) != FALSE) {
- Flags |= NET_PACKET_FLAG_IP_CHECKSUM_FAILED;
- }
- }
- if (Protocol == RTL81_RECEIVE_DESCRIPTOR_COMMAND_PROTOCOL_UDP_IP) {
- Flags |= NET_PACKET_FLAG_UDP_CHECKSUM_OFFLOAD;
- if (RTL81_RECEIVE_UDP_CHECKSUM_FAILURE(Command) != FALSE) {
- Flags |= NET_PACKET_FLAG_UDP_CHECKSUM_FAILED;
- }
- } else if (Protocol ==
- RTL81_RECEIVE_DESCRIPTOR_COMMAND_PROTOCOL_TCP_IP) {
- Flags |= NET_PACKET_FLAG_TCP_CHECKSUM_OFFLOAD;
- if (RTL81_RECEIVE_TCP_CHECKSUM_FAILURE(Command) != FALSE) {
- Flags |= NET_PACKET_FLAG_TCP_CHECKSUM_FAILED;
- }
- }
- }
- Packet.Buffer = DefaultData->ReceivePacketData +
- (NextToReap * RTL81_RECEIVE_BUFFER_DATA_SIZE);
- Packet.BufferPhysicalAddress = Descriptor->PhysicalAddress;
- Packet.Flags = Flags;
- //
- // Discard the CRC from the size.
- //
- Size -= RTL81_RECEIVE_CRC_LENGTH;
- Packet.BufferSize = Size;
- Packet.DataSize = Size;
- Packet.DataOffset = 0;
- Packet.FooterOffset = Size;
- NetProcessReceivedPacket(Device->NetworkLink, &Packet);
- }
- return;
- }
- KSTATUS
- Rtl81pReadMacAddress (
- PRTL81_DEVICE Device
- )
- /*++
- Routine Description:
- This routine reads the MAC address out of the EEPROM on the RTL81xx. The
- MAC address will be stored in the device structure.
- Arguments:
- Device - Supplies a pointer to the RTL81xx device.
- Return Value:
- Status code.
- --*/
- {
- RTL81_REGISTER AddressRegister;
- ULONG Index;
- USHORT MacValue;
- //
- // The MAC address is in the individual address registers. There is one
- // byte in each but two can be read at a time as they are sequential
- // registers.
- //
- AddressRegister = Rtl81RegisterId0;
- for (Index = 0; Index < sizeof(Device->MacAddress); Index += 2) {
- MacValue = RTL81_READ_REGISTER16(Device, AddressRegister);
- Device->MacAddress[Index] = (BYTE)MacValue;
- Device->MacAddress[Index + 1] = (BYTE)(MacValue >> BITS_PER_BYTE);
- AddressRegister += 2;
- }
- //
- // Check to determine if this is a valid MAC address.
- //
- if (NetIsEthernetAddressValid(Device->MacAddress) == FALSE) {
- return STATUS_INVALID_ADDRESS;
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- Rtl81pReadMdio (
- PRTL81_DEVICE Device,
- RTL81_MII_REGISTER Register,
- PULONG Data
- )
- /*++
- Routine Description:
- This routine performs an MDIO register read.
- Arguments:
- Device - Supplies a pointer to the device.
- Register - Supplies the register to read.
- Data - Supplies a pointer where the register contents will be returned on
- success.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG CurrentTime;
- ULONG RegisterValue;
- ULONGLONG Timeout;
- ULONGLONG TimeoutTicks;
- TimeoutTicks = HlQueryTimeCounterFrequency() * RTL81_DEVICE_TIMEOUT;
- ASSERT(Register < Rtl81MiiRegisterMax);
- RegisterValue = RTL81_MII_ACCESS_READ |
- ((Register << RTL81_MII_ACCESS_REGISTER_SHIFT) &
- RTL81_MII_ACCESS_REGISTER_MASK);
- RTL81_WRITE_REGISTER32(Device, Rtl81RegisterMiiAccess, RegisterValue);
- CurrentTime = KeGetRecentTimeCounter();
- Timeout = CurrentTime + TimeoutTicks;
- do {
- KeDelayExecution(FALSE, FALSE, 100);
- RegisterValue = RTL81_READ_REGISTER32(Device, Rtl81RegisterMiiAccess);
- if ((RegisterValue & RTL81_MII_ACCESS_COMPLETE_MASK) ==
- RTL81_MII_ACCESS_READ_COMPLETE) {
- *Data = (RegisterValue & RTL81_MII_ACCESS_DATA_MASK) >>
- RTL81_MII_ACCESS_DATA_SHIFT;
- KeDelayExecution(FALSE, FALSE, 20);
- break;
- }
- CurrentTime = KeGetRecentTimeCounter();
- } while (CurrentTime <= Timeout);
- if (CurrentTime > Timeout) {
- return STATUS_TIMEOUT;
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- Rtl81pWriteMdio (
- PRTL81_DEVICE Device,
- RTL81_MII_REGISTER Register,
- ULONG Data
- )
- /*++
- Routine Description:
- This routine performs an MDIO register write.
- Arguments:
- Device - Supplies a pointer to the device.
- Register - Supplies the register to read.
- Data - Supplies the data to write to the register.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG CurrentTime;
- ULONG RegisterValue;
- ULONGLONG Timeout;
- ULONGLONG TimeoutTicks;
- TimeoutTicks = HlQueryTimeCounterFrequency() * RTL81_DEVICE_TIMEOUT;
- ASSERT(Register < Rtl81MiiRegisterMax);
- ASSERT((Data & ~RTL81_MII_ACCESS_DATA_MASK) == 0);
- RegisterValue = RTL81_MII_ACCESS_WRITE |
- ((Register << RTL81_MII_ACCESS_REGISTER_SHIFT) &
- RTL81_MII_ACCESS_REGISTER_MASK) |
- Data;
- RTL81_WRITE_REGISTER32(Device, Rtl81RegisterMiiAccess, RegisterValue);
- CurrentTime = KeGetRecentTimeCounter();
- Timeout = CurrentTime + TimeoutTicks;
- do {
- KeDelayExecution(FALSE, FALSE, 100);
- RegisterValue = RTL81_READ_REGISTER32(Device, Rtl81RegisterMiiAccess);
- if ((RegisterValue & RTL81_MII_ACCESS_COMPLETE_MASK) ==
- RTL81_MII_ACCESS_WRITE_COMPLETE) {
- KeDelayExecution(FALSE, FALSE, 20);
- break;
- }
- CurrentTime = KeGetRecentTimeCounter();
- } while (CurrentTime <= Timeout);
- if (CurrentTime > Timeout) {
- return STATUS_TIMEOUT;
- }
- return STATUS_SUCCESS;
- }
|