diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/ndis/dc21x4/interrup.c | 1726 |
1 files changed, 1726 insertions, 0 deletions
diff --git a/private/ntos/ndis/dc21x4/interrup.c b/private/ntos/ndis/dc21x4/interrup.c new file mode 100644 index 000000000..9de60bc52 --- /dev/null +++ b/private/ntos/ndis/dc21x4/interrup.c @@ -0,0 +1,1726 @@ +/*+ + * file: interrup.c + * + * Copyright (C) 1992-1995 by + * Digital Equipment Corporation, Maynard, Massachusetts. + * All rights reserved. + * + * This software is furnished under a license and may be used and copied + * only in accordance of the terms of such license and with the + * inclusion of the above copyright notice. This software or any other + * copies thereof may not be provided or otherwise made available to any + * other person. No title to and ownership of the software is hereby + * transferred. + * + * The information in this software is subject to change without notice + * and should not be construed as a commitment by digital equipment + * corporation. + * + * Digital assumes no responsibility for the use or reliability of its + * software on equipment which is not supplied by digital. + * + * + * Abstract: This file contains the interrupt handling routines for + * the NDIS 4.0 miniport driver for DEC's DC21X4 Ethernet + * controller family . + * + * Author: Philippe Klein + * + * Revision History: + * + * phk 09-Aug-1994 Initial entry + * phk 09-Feb-1995 V2.0 + * +-*/ + +#include <precomp.h> + + + + + + + + + + + + +// Logging code to keep track of receive buffers and packets. + +#if DBG +#define PACKET_LOG_SIZE 1024 + +typedef struct _PACKET_LOG { + + PNDIS_PACKET Packet; + PRCV_HEADER RcvHeader; + ULONG Ident1; + ULONG Ident2; + +}PACKET_LOG,*PPACKET_LOG; + + +UINT dc21x4CurrentLogEntry = (PACKET_LOG_SIZE - 1); +PPACKET_LOG dc21x4PacketLogHead = NULL; +PACKET_LOG dc21x4PacketLog[PACKET_LOG_SIZE] = {0}; + +VOID DC21X4LogPacket(PNDIS_PACKET Packet, PRCV_HEADER RcvHeader, UINT Ident1, UINT Ident2) { + + dc21x4PacketLogHead = &dc21x4PacketLog[dc21x4CurrentLogEntry]; + + dc21x4PacketLogHead->Packet = Packet; + dc21x4PacketLogHead->RcvHeader = RcvHeader; + dc21x4PacketLogHead->Ident1 = Ident1; + dc21x4PacketLogHead->Ident2 = Ident2; + + if (dc21x4CurrentLogEntry-- == 0) { + dc21x4CurrentLogEntry = (PACKET_LOG_SIZE - 1); + } +} +#else + +#define DC21X4LogPacket(Packet, RcvHeader, Ident1, Ident2) + +#endif + + + + + + + + + + + + +/*+ + * + * DC21X4Isr + * + * Routine Description: + * + * Interrupt service routine. + * Get the value of ISR and clear the adapter's interrupt status + * +-*/ + +extern +VOID +DC21X4Isr( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueMiniportHandleInterrupt, + IN NDIS_HANDLE MiniportAdapterContext + ) +{ + + PDC21X4_ADAPTER Adapter; + ULONG Status; + ULONG IsrStatus; + +#if _DBG + DbgPrint("DC21X4Isr\n"); +#endif + + Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; + + // Read the interrupt field of the adapter's Status CSR + + DC21X4_READ_PORT( + DC21X4_STATUS, + &Status + ); + + IsrStatus = Status & DC21X4_STATUS_INTERRUPTS; + +#if _DBG + DbgPrint("ISR[%08x] Interrupt Status = %08x\n",Adapter,IsrStatus); +#endif + + // Check if the shared interrupt is recognized by the adapter + + if (IsrStatus == 0) { + + *InterruptRecognized = FALSE; + *QueueMiniportHandleInterrupt = FALSE; + return; + } + + *InterruptRecognized = TRUE; + + //Mask the interrupts + //(shared interrupts should be disabled in the ISR). + + DC21X4_WRITE_PORT( + DC21X4_INTERRUPT_MASK, + 0 + ); + + //Clear the interrupts + + DC21X4_WRITE_PORT( + DC21X4_STATUS, + Status + ); + + if (IsrStatus & DC21X4_SYSTEM_ERROR) { + + // This is a fatal error caused by a system hardware + // failure: stop the DC21X4 chip +#if __DBG + DbgPrint("\n\nDC21X4_SYSTEM_ERROR!!!\n\n"); +#endif + Adapter->ParityError = TRUE; + + DC21X4StopAdapter(Adapter); + + *QueueMiniportHandleInterrupt = FALSE; + return; + } + +#if __DBG + if (IsrStatus & DC21X4_LINK_FAIL) { + DbgPrint("ISR: LinkFail interrupt\n"); + } + else if (IsrStatus & DC21X4_LINK_PASS) { + DbgPrint("ISR: LinkPass interrupt\n"); + } +#endif + + // count the number of Rcv & Txm interrupts + + if ( (IsrStatus & Adapter->InterruptMask) + & (DC21X4_RCV_INTERRUPTS | DC21X4_TXM_INTERRUPTS)) { + Adapter->InterruptCount++; + } + + Adapter->InterruptStatus |= IsrStatus; + *QueueMiniportHandleInterrupt = TRUE; + return; + +} + + + + + + + + + + + + +/*++ + * + * DC21X4SynchClearIsr + * + * Routine Description: + * + * This routine is used by the interrupt handler to synchronize + * with the interrupt service routine while accessing the shared + * ISR value. + * + * The routine clears the Adapter's Interrupt Status CSR + * + * Arguments: + * + * SyncContext - A pointer to a structure storing a pointer to the + * adapter and the ISR Status value. + * + * Return Value: + * + * None + * +-*/ + +VOID +DC21X4SynchClearIsr( + IN PDC21X4_SYNCH_CONTEXT SyncContext + ) +{ + PDC21X4_ADAPTER Adapter = SyncContext->Adapter; + +#if _DBG + DbgPrint("DC21X4SynchClearIsr [%08x]\n", + ( DC21X4_RCV_INTERRUPTS + | DC21X4_TXM_INTERRUPTS + | SyncContext->IsrStatus)); +#endif + + //Clear the interrupt status + + DC21X4_WRITE_PORT( + DC21X4_STATUS, + ( DC21X4_RCV_INTERRUPTS + | DC21X4_TXM_INTERRUPTS + | SyncContext->IsrStatus) + ); + +} + + + + + + + + + + + + +/*++ + * + * DC21X4HandleInterrupt + * + * Routine Description: + * + * This routine is queued by the interrupt service routine and + * handle the routines associated with the interrupts + * +-*/ + +extern +VOID +DC21X4HandleInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ) + +{ + + PDC21X4_ADAPTER Adapter; + PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor; + PDC21X4_TRANSMIT_DESCRIPTOR TransmitDescriptor; + + DC21X4_SYNCH_CONTEXT SyncContext; + + ULONG Status; + ULONG IsrStatus; + +#if _DBG + DbgPrint("DC21X4HandleInterrupt\n"); +#endif + + Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; + SyncContext.Adapter = Adapter; + + while (TRUE) { + + IsrStatus = Adapter->InterruptStatus; + SyncContext.IsrStatus = IsrStatus; + + if (IsrStatus & ( DC21X4_LINK_FAIL + | DC21X4_LINK_PASS + | DC21X4_GEP_INTERRUPT + ) + ) { + + if (IsrStatus & DC21X4_GEP_INTERRUPT) { + HandleGepInterrupt(Adapter); + } + if (IsrStatus & DC21X4_LINK_FAIL) { + HandleLinkFailInterrupt(Adapter,&IsrStatus); + } + if (IsrStatus & DC21X4_LINK_PASS) { + HandleLinkPassInterrupt(Adapter,&IsrStatus); + } + } + + // Clear the Interrupt Status CSR + + + NdisMSynchronizeWithInterrupt( + &Adapter->Interrupt, + DC21X4SynchClearIsr, + &SyncContext + ); + + if (Adapter->ResetInProgress) { + return; + } + + // Check the Receive and Transmit Descriptor + // rings to process any pending packet + + ReceiveDescriptor = + ProcessReceiveDescRing (Adapter); + + TransmitDescriptor = + ProcessTransmitDescRing (Adapter); + + + // Check if there is more work to do + + DC21X4_READ_PORT( + DC21X4_STATUS, + &Status + ); + + Adapter->InterruptStatus = + Status & DC21X4_STATUS_INTERRUPTS; + + if (Adapter->InterruptStatus) { + continue; + } + +#if _DBG + DbgPrint("Rcv Status %08x\n",ReceiveDescriptor->Status); +#endif + if ((ReceiveDescriptor->Status & DC21X4_RDES_OWN_BIT) == DESC_OWNED_BY_SYSTEM) { + // More Receive frames should be processed + continue; + } + +#if _DBG + DbgPrint("Txm Status %08x\n",TransmitDescriptor->Status); +#endif + if (Adapter->DequeueTransmitDescriptor == Adapter->EnqueueTransmitDescriptor) { + break; + } + + else if ((TransmitDescriptor->Status & DC21X4_TDES_OWN_BIT) == DESC_OWNED_BY_DC21X4) { + + // The transmit ring contains Txm descriptor(s): Poll_transmit + // the adapter + // (if Txm is running (expected case), this is a no_op + // if Txm is suspendend (abnormal case caused by Motorola + // Eagle chip set's cache coherency problem) the transmission + // will resume) + DC21X4_WRITE_PORT( + DC21X4_TXM_POLL_DEMAND, + 1 + ); + break; + } + } + + if (Adapter->Polling) { + + //Restart the monitor timer + + DC21X4_WRITE_PORT( + DC21X4_TIMER, + Adapter->Polling + ); + } + +#if _DBG + DbgPrint("Interrupt Handler completed\n"); +#endif + +} + + + + +/*+ + * + * HandleGepInterrupt + * + * Routine Description: + * + * Handle the GEP interrupt + * + * Arguments: + * + * Adapter - The adapter to indicate to. + * + * Return Value: + * + * None. + * +-*/ +VOID +HandleGepInterrupt( + IN PDC21X4_ADAPTER Adapter + ) +{ + ULONG Gep; +#if __DBG + DbgPrint("Handle GEP interrupt\n"); +#endif + + //Read the GEP register + + DC21X4_READ_PORT( + DC21X4_SIA_MODE_2, + &Gep + ); + + if ( (Gep & Adapter->Phy[Adapter->PhyNumber].GepInterruptMask) + && (Adapter->PhyMediumInSrom) + ) { + +#if __DBG + DbgPrint("GEP Interrupt:\n"); +#endif + // A MII card was plugged in: Initialize the PHY + + DC21X4IndicateMediaStatus(Adapter,LinkFail); + +#if __DBG + DbgPrint("Init the PHY...\n"); +#endif + Adapter->PhyPresent = DC21X4PhyInit(Adapter); +#if __DBG + DbgPrint("Adapter->PhyPresent=%d\n",Adapter->PhyPresent); +#endif + + if (Adapter->PhyPresent) { + + DC21X4SetPhyConnection( + Adapter + ); + + if ( (Adapter->PhyNwayCapable) + && (Adapter->MediaType & MEDIA_NWAY) + ) { + //PHY is Nway capable: disable DC21X4's Nway + DC21X4DisableNway (Adapter); + } + + // Start the AutoSense timer + DC21X4StartAutoSenseTimer( + Adapter, + (UINT)0 + ); + } + } + +} + + + + + +/*+ + * + * HandleLinkFailInterrupt + * + * Routine Description: + * + * Handle the Link_Fail interrupt + * + * Arguments: + * + * Adapter - The adapter to indicate to. + * IsrStatus - Interrupt status + * Return Value: + * + * None. + * +-*/ +VOID +HandleLinkFailInterrupt( + IN PDC21X4_ADAPTER Adapter, + IN OUT PULONG IsrStatus + ) +{ + +#if __DBG + DbgPrint("Handle Link Fail interrupt\n"); +#endif + + if (Adapter->SelectedMedium != Medium10BaseT) { + return; + } + + if (Adapter->PhyPresent) { + + DC21X4SetPhyControl( + Adapter, + MiiGenAdminRelease10 + ); + + } + + switch (Adapter->DeviceId) { + + case DC21040_CFID: + + DC21X4IndicateMediaStatus(Adapter,LinkFail); + *IsrStatus &= ~( + DC21X4_LINK_PASS + ); + + //21040 does not provide a Link_pass interrupt: + //Start the AutoSense timer to poll on Link Pass + + DC21X4StartAutoSenseTimer( + Adapter, + DC21X4_SPA_TICK + ); + return; + + case DC21142_CFID: + + Adapter->Indicate10BTLink = FALSE; + + case DC21041_CFID: + + switch (Adapter->LinkHandlerMode) { + + case NwayWorkAround: + + DC21X4IndicateMediaStatus(Adapter,LinkFail); + *IsrStatus &= ~( + DC21X4_LINK_PASS + ); + + if ((!Adapter->NwayEnabled) && (Adapter->MediaNway)) { + + SwitchMediumToTpNway(Adapter); + + } + break; + + case Nway: + + DC21X4IndicateMediaStatus(Adapter,LinkFail); + *IsrStatus &= ~( + DC21X4_LINK_PASS + ); + + if ((Adapter->MediaType & MEDIA_AUTOSENSE) + ||(Adapter->MediaNway) + ){ + + //Stop the Link Timer if active + if (Adapter->TimerFlag != NoTimer) { + DC21X4StopAutoSenseTimer(Adapter); + } + + //Start the Anc Timer to timeout if the + //Nway autonegotiation does not complete + + Adapter->TimerFlag=AncTimeout; + + NdisMSetTimer( + &Adapter->Timer, + DC21X4_ANC_TIMEOUT + ); + } + break; + + + default: + + DC21X4IndicateMediaStatus(Adapter,LinkFail); + *IsrStatus &= ~( + DC21X4_LINK_PASS + ); + + if (Adapter->MediaType & MEDIA_AUTOSENSE) { + + DC21X4SwitchMedia( + Adapter, + Medium10Base2_5 + ); + } + else if (Adapter->MediaType & MEDIA_NWAY) { + + //Stop the Link Timer if active + if (Adapter->TimerFlag != NoTimer) { + DC21X4StopAutoSenseTimer(Adapter); + } + + //Start the Anc Timer to timeout if the + //Nway autonegotiation does not complete + + Adapter->TimerFlag=AncTimeout; + + NdisMSetTimer( + &Adapter->Timer, + DC21X4_ANC_TIMEOUT + ); + } + break; + } + } + +} + + + + +/*+ + * + * HandleLinkPassInterrupt + * + * Routine Description: + * + * Handle the LinkPass/ANC interrupt + * + * Arguments: + * + * Adapter - The adapter to indicate to. + * IsrStatus - Interrupt status + * Return Value: + * + * None. + * +-*/ +VOID +HandleLinkPassInterrupt( + IN PDC21X4_ADAPTER Adapter, + IN OUT PULONG IsrStatus + ) +{ + + INT i; + +#if __DBG + DbgPrint("Handle Link Pass interrupt\n"); +#endif + + + switch (Adapter->DeviceId) { + + case DC21041_CFID: + case DC21142_CFID: + switch (Adapter->LinkHandlerMode) { + + case NwayWorkAround: + + if (Adapter->TimerFlag==AncPolling){ + return; + } + else if ( (Adapter->SelectedMedium != Medium10BaseT) + || (Adapter->FirstAncInterrupt)) { + + SwitchMediumToTpNway(Adapter); + } + + else { + DC21X4IndicateMediaStatus(Adapter,LinkPass); + } + + Adapter->FirstAncInterrupt = FALSE; + return; + + case Nway: + + if (Adapter->MediaNway) { + + //NWAY enabled: Auto_Negotiation_Completed interrupt +#if __DBG + DbgPrint("AutoNegotiation Completed\n"); +#endif + //Stop the Anc or Spa timer if active + if (Adapter->TimerFlag != NoTimer) { + DC21X4StopAutoSenseTimer(Adapter); + } + + //Start the Link timer to defer the + //Link Status check + Adapter->TimerFlag=DeferredLinkCheck; + NdisMSetTimer( + &Adapter->Timer, + DC21X4_LINK_DELAY + ); + + return; + } + + default: + + //No NWAY: Link Pass interrupt + + if (Adapter->SelectedMedium != Medium10BaseT) { + + if (Adapter->MediaType & MEDIA_AUTOSENSE) { + + if ( (Adapter->TimerFlag != NoTimer) + && (!Adapter->PhyPresent) ){ + + DC21X4StopAutoSenseTimer(Adapter); + } + + //Switch to 10BaseT + DC21X4SwitchMedia( + Adapter, + Medium10BaseT + ); + } + } + else { + + if (Adapter->PhyPresent) { + + // Deferred the indicaton of the 10BT link + // to poll first the PHY Link status + // to check if the link interrupt + // is not a false 10BT link generated by + // 100BTx pulses. + + Adapter->Indicate10BTLink = TRUE; + return; + + } + DC21X4IndicateMediaStatus(Adapter,LinkPass); + + } + return; + + + } + break; + + default: + + DC21X4IndicateMediaStatus(Adapter,LinkPass); + } + +} + + + +/*+ + * + * SwitchMediumToTpNway + * + * Routine Description: + * + * Switch Medium to 10BaseT with Nway enabled + * + * Arguments: + * + * Adapter - The adapter to indicate to. + * + * Return Value: + * + * None. + * +-*/ +VOID +SwitchMediumToTpNway( + IN PDC21X4_ADAPTER Adapter + ) +{ + + //Stop the Spa timer if active + + if (Adapter->TimerFlag != NoTimer) { + DC21X4StopAutoSenseTimer(Adapter); + } + + //Switch medium to TP with Nway enabled : + + DC21X4SwitchMedia( + Adapter, + Medium10BaseTNway + ); + + Adapter->AutoNegotiationCount = 0; + + //Initialize the Poll timeout counter + Adapter->PollCount= POLL_COUNT_TIMEOUT; + + //Start the Poll timer to + //poll the AutoNegotiation State + + Adapter->TimerFlag=AncPolling; + NdisMSetTimer( + &Adapter->Timer, + DC21X4_POLL_DELAY + ); + +} + + + + + +/*+ + * + * ProcessReceiveDescRing + * + * Routine Description: + * + * Process the packets that have finished receiving. + * + * Arguments: + * + * Adapter - The adapter to indicate to. + * + * Return Value: + * + * None. + * +-*/ +PDC21X4_RECEIVE_DESCRIPTOR +ProcessReceiveDescRing( + IN PDC21X4_ADAPTER Adapter + ) +{ + + // Walk down the receive descriptors ring starting at the + // last known descriptor owned by the adapter + // + // Examine each receive ring descriptor for errors. + // + // When we have the entire packet (and error processing doesn't + // prevent us from indicating it), we give the routine that + // processes the packet through the filter, the buffers virtual + // address (which is always the lookahead size) and as the + // MAC context the address of the first data byte. + + PDC21X4_RECEIVE_DESCRIPTOR CurrentDescriptor; + + PVOID FrameVa; + USHORT FrameType; + + UINT FrameSize; + UINT LookAheadSize; + + BOOLEAN fStopReceiveProcessing = FALSE; + + PRCV_HEADER RcvHeader; + PNDIS_PACKET Packet; + PPNDIS_PACKET pPktArray; + PNDIS_BUFFER Buffer; + ULONG Length; + UINT Index; + UINT Count; + UINT i; + PDC21X4_RECEIVE_DESCRIPTOR DescriptorMark; + ULONG Status; + ULONG Register; + INT Timeout; + ULONG OverflowCount; + ULONG MissedFrames; + + NDIS_PHYSICAL_ADDRESS Pa; + +#if _DBG + DbgPrint("ProcessReceiveInterrupts\n"); +#endif + + NdisSetPhysicalAddressHigh(Pa,0); + DescriptorMark = Adapter->DequeueReceiveDescriptor; + + while (!fStopReceiveProcessing) { + + // Grab a max of MAX_PACKET_ARRAY packets at a time. + + for (Count = 0, pPktArray = Adapter->PacketArray; Count < MAX_PACKET_ARRAY;) { + + // Get the current receive descriptor. + + CurrentDescriptor = Adapter->DequeueReceiveDescriptor; +#if _DBG + DbgPrint("RcvDesc [%08x]\n",CurrentDescriptor); +#endif + + // If the descriptor is not owned by the system, we are done. + + if ((CurrentDescriptor->Status & DC21X4_RDES_OWN_BIT) != DESC_OWNED_BY_SYSTEM) { + fStopReceiveProcessing = TRUE; + break; + } + + if (Adapter->OverflowWorkAround) { + + if (CurrentDescriptor==DescriptorMark) { + + // Mark the next descriptor not owned by the system into the ring + + do { + DescriptorMark = DescriptorMark->Next; + } + while ( + ((DescriptorMark->Status & DC21X4_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4) + && (DescriptorMark != Adapter->DequeueReceiveDescriptor) + ); + + if (!Adapter->IndicateOverflow) { + + //Check if an overflow occured for at least one + // of the packets currently queued into the Rcv ring + + DC21X4_READ_PORT( + DC21X4_MISSED_FRAME, + &Register + ); + + MissedFrames = Register & DC21X4_MISSED_FRAME_COUNTER; + if (MissedFrames) { + Adapter->GeneralMandatory[GM_MISSED_FRAMES] += MissedFrames; + } + OverflowCount = (Register >> DC21X4_OVERFLOW_COUNTER_SHIFT) + & DC21X4_OVERFLOW_COUNTER; + if (OverflowCount) { + Adapter->IndicateOverflow = TRUE; + Adapter->MediaOptional[MO_RECEIVE_OVERFLOW]+= OverflowCount; + } + + } + + if (Adapter->IndicateOverflow) { + + //Stop the Receiver + DC21X4_WRITE_PORT( + DC21X4_OPERATION_MODE, + Adapter->OperationMode & ~(DC21X4_RCV_START) + ); + + // Discard the packets queued into the ring: + // Reclaim all the descriptors owned by the system + + + while (((Adapter->DequeueReceiveDescriptor)->Status & DC21X4_RDES_OWN_BIT) + == DESC_OWNED_BY_SYSTEM + ) { + + (Adapter->DequeueReceiveDescriptor)->Status = DESC_OWNED_BY_DC21X4; + Adapter->MediaOptional[MO_RECEIVE_OVERFLOW]++; + Adapter->DequeueReceiveDescriptor = (Adapter->DequeueReceiveDescriptor)->Next; + } + + Adapter->IndicateOverflow = FALSE; + + // Wait for the Receiver to stop + Timeout = DC21X4_RVC_TIMEOUT; + + while (Timeout--) { + + DC21X4_READ_PORT( + DC21X4_STATUS, + &Status + ); + + if ((Status & (DC21X4_RCV_PROCESS_STATE)) == 0) { + break; + } + NdisStallExecution(2*MILLISECOND); + } + + // Once the Receiver is stopped reclaim the descriptors + // owned by the system (this happends if a reception was + // in progress when tyhe stop_receive command was issued + + while (((Adapter->DequeueReceiveDescriptor)->Status & DC21X4_RDES_OWN_BIT) + == DESC_OWNED_BY_SYSTEM + ) { + + (Adapter->DequeueReceiveDescriptor)->Status = DESC_OWNED_BY_DC21X4; + Adapter->MediaOptional[MO_RECEIVE_OVERFLOW]++; + Adapter->DequeueReceiveDescriptor = (Adapter->DequeueReceiveDescriptor)->Next; + } + + // Restart the Receiver + DC21X4_WRITE_PORT( + DC21X4_OPERATION_MODE, + Adapter->OperationMode + ); + + DescriptorMark = Adapter->DequeueReceiveDescriptor; + //leave the "for Count" loop back to the "while" loop + break; + } + + } + + } + + Adapter->DequeueReceiveDescriptor = CurrentDescriptor->Next; + + if (!(CurrentDescriptor->Status & DC21X4_RDES_ERROR_SUMMARY)) { + + // The frame was received correctly + + FrameSize = ((CurrentDescriptor->Status & DC21X4_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER) + - ETH_CRC_SIZE; + + // Get a pointer to the receive buffer header. + + RcvHeader = CurrentDescriptor->RcvHeader; + ASSERT(RcvHeader->Signature == 'dHxR'); + + FrameVa = (PVOID)(RcvHeader->Va); + + NdisFlushBuffer( + RcvHeader->FlushBuffer, + FALSE + ); + + NdisSetPhysicalAddressLow(Pa,RcvHeader->Pa); + + NdisMUpdateSharedMemory( + Adapter->MiniportAdapterHandle, + RcvHeader->Size, + (PVOID)RcvHeader->Va, + Pa + ); + + // Adjust the length of the flush buffer to the + // length of the packet. + + NdisAdjustBufferLength( + RcvHeader->FlushBuffer, + FrameSize + ); + + + // Save the packet in the packet array. + + Packet = RcvHeader->Packet; + *pPktArray = Packet; + + // Log the packet. + + DC21X4LogPacket(Packet, RcvHeader, '-', Count); + // Update the statistics based on Receive status; +#if _DBG + DbgPrint("Receive ok\n"); +#endif + Adapter->GeneralMandatory[GM_RECEIVE_OK]++; + + // DC21X4 flags Rcv Multicast address but does not + // support a specific flag for Rcv Broadcast address + + if (CurrentDescriptor->Status & DC21X4_RDES_MULTICAST_FRAME) { + FrameType = (IS_BROADCAST (FrameVa)) ? RCV_BROADCAST_FRAME: RCV_MULTICAST_FRAME; + } + else { + FrameType = RCV_DIRECTED_FRAME; + } +#if _DBG + DbgPrint("FrameType = %d\n",FrameType); +#endif + Adapter->GeneralOptionalCount[FrameType].FrameCount++; + + ADD_ULONG_TO_LARGE_INTEGER( + Adapter->GeneralOptionalCount[FrameType].ByteCount, + FrameSize + ); + // Can the binding keep the packet? + + if (Adapter->FreeRcvList != NULL) { + + NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_SUCCESS); + + // Remove the receive buffer from the ring + // and replace it with an extra one. + + RcvHeader = Adapter->FreeRcvList; + Adapter->FreeRcvList = RcvHeader->Next; + + Adapter->CurrentReceiveBufferCount--; + + // Setup a new receive buffer for the current descriptor. + + CurrentDescriptor->RcvHeader = RcvHeader; + CurrentDescriptor->FirstBufferAddress = RcvHeader->Pa; + CurrentDescriptor->Status = DESC_OWNED_BY_DC21X4; + } + else { + + // Mark the packet as copy only... + + NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_RESOURCES); + + Adapter->NeededReceiveBuffers++; + RCV_RESERVED(Packet)->Descriptor = CurrentDescriptor; + } + + Count ++; + pPktArray ++; + } + else { + + // The frame was received with errors: + // Update the statistics based on the Receive status. +#if _DBG + DbgPrint("Receive_error: DescStatus = %08x\n",CurrentDescriptor->Status); +#endif + Adapter->GeneralMandatory[GM_RECEIVE_ERROR]++; + + if (CurrentDescriptor->Status & DC21X4_RDES_DRIBBLING_BIT) { +#if _DBG + DbgPrint(" Rcv Alignment Error\n"); +#endif + Adapter->MediaMandatory[MM_RECEIVE_ALIGNMENT_ERROR]++; + } + else if (CurrentDescriptor->Status & DC21X4_RDES_CRC_ERROR) { +#if _DBG + DbgPrint(" Rcv CRC Error\n"); +#endif + Adapter->GeneralOptional[GO_RECEIVE_CRC_ERROR]++; + } + + if (CurrentDescriptor->Status & DC21X4_RDES_OVERFLOW) { +#if _DBG + DbgPrint(" Rcv Overflow\n"); +#endif + Adapter->MediaOptional[MO_RECEIVE_OVERFLOW]++; + } + + CurrentDescriptor->Status = DESC_OWNED_BY_DC21X4; + } + + } + + // Did we get any packets to indicate up? + + if (Count != 0) { + + + // Indicate the packets up to the filter library. + + NdisMIndicateReceivePacket(Adapter->MiniportAdapterHandle, + Adapter->PacketArray, + Count); + + + // Determine which packets were kept and which ones + // were not. + + for (i = 0, pPktArray = Adapter->PacketArray; + i < Count; + i++, pPktArray ++) { + + // If the status code for the packet is not + // status pending then we can place the resources back + // on the free lists. + + if (NDIS_GET_PACKET_STATUS(*pPktArray) != NDIS_STATUS_PENDING) { + + // Get a pointer to the receive header. + + RcvHeader = RCV_RESERVED(*pPktArray)->RcvHeader; + ASSERT(RcvHeader->Signature == 'dHxR'); + + DC21X4LogPacket(*pPktArray, RcvHeader, '+', i); + + // Adjust the buffer length. + + NdisAdjustBufferLength( + RcvHeader->FlushBuffer, + DC21X4_MAX_FRAME_SIZE + ); + + // If we indicated to the binding that it couldn't + // keep this packet then don't place it back on the + // list!!! + + if (NDIS_GET_PACKET_STATUS(*pPktArray) == NDIS_STATUS_RESOURCES) { + RCV_RESERVED(*pPktArray)->Descriptor->Status = DESC_OWNED_BY_DC21X4; + } + else { + + // Place the buffer back on the free queue. + + RcvHeader->Next = Adapter->FreeRcvList; + Adapter->FreeRcvList = RcvHeader; + } + } + } + } + } + return CurrentDescriptor; + +} + + + + + + + + + + +/*+ + * + * ProcessTransmitDescRing + * + * Routine Description: + * + * Process the packets that have finished transmitting + * + * Arguments: + * + * Adapter - The adapter to indicate to. + * + * Return Value: + * + * None. + * +-*/ + + +PDC21X4_TRANSMIT_DESCRIPTOR +ProcessTransmitDescRing( + IN PDC21X4_ADAPTER Adapter + ) +{ + + PDC21X4_TRANSMIT_DESCRIPTOR CurrentDescriptor; + PDC21X4_TRANSMIT_DESCRIPTOR Descptr; + UINT Collisions; + NDIS_STATUS NdisStatus; + UINT MapPtr; + ULONG ProcessStatus; + ULONG DescOwnership; + + ULONG TxmDescriptorCount = 0; + ULONG MapRegistersCount = 0; + ULONG MaxTransmitBufferCount = 0; + ULONG MinTransmitBufferCount = 0; + ULONG GoTransmitCount = 0; + +#if _DBG + DbgPrint("ProcessTransmitInterrupts\n"); +#endif + + // If the Transmit descriptor ring is not empty, + // walk the ring from the last known descriptor owned by the adapter + + while (Adapter->DequeueTransmitDescriptor != Adapter->EnqueueTransmitDescriptor) { + + CurrentDescriptor = Adapter->DequeueTransmitDescriptor; + + // If the current descriptor is not owned by the system, we are done. + + if ((CurrentDescriptor->Status & DC21X4_TDES_OWN_BIT) != DESC_OWNED_BY_SYSTEM) { + break; + } + + if (CurrentDescriptor->Control & DC21X4_TDES_SETUP_PACKET) { + +#if _DBG + DbgPrint("Int: TxmDesc %08x - Setup desc.\n",CurrentDescriptor); +#endif + // Setup buffer + // Complete the pended Set Information request + // which originated the CAM load + +#if _DBG + DbgPrint("Complete Set Information\n"); +#endif + NdisMSetInformationComplete ( + Adapter->MiniportAdapterHandle, + NDIS_STATUS_SUCCESS + ); + + if ( (Adapter->DeviceId == DC21040_CFID) + && (Adapter->RevisionNumber == DC21040_REV1)) { + + // SFD bug workaround : + // Restart the Receiver and Enable the Sia + + DC21X4_WRITE_PORT( + DC21X4_OPERATION_MODE, + Adapter->OperationMode + ); + + DC21X4_WRITE_PORT( + DC21X4_SIA_MODE_0, + Adapter->Media[Adapter->SelectedMedium].SiaRegister[0] + ); + } + + TxmDescriptorCount++; + Adapter->DequeueTransmitDescriptor = CurrentDescriptor->Next; + + } + + else if (CurrentDescriptor->Control & DC21X4_TDES_LAST_SEGMENT) { + +#if _DBG + DbgPrint("Int: TxmDesc %08x - Last segment desc.\n",CurrentDescriptor); +#endif + // if Underrun check if the packet should be requeued + if ( (CurrentDescriptor->Status & DC21X4_TDES_UNDERRUN_ERROR) + && (Adapter->UnderrunRetryCount < Adapter->UnderrunMaxRetries) + ) { + + // The Txm packet can only be requeued + // if the Txm process has not been restarted + // by a Txm Poll demand + + Adapter->DisableTransmitPolling = TRUE; + + DC21X4_READ_PORT( + DC21X4_STATUS, + &ProcessStatus + ); + + ProcessStatus &= DC21X4_TXM_PROCESS_STATE; + + DescOwnership = (CurrentDescriptor->Next != Adapter->EnqueueTransmitDescriptor) ? + (CurrentDescriptor->Next)->Status & DC21X4_TDES_OWN_BIT : + DESC_OWNED_BY_DC21X4; + + if ((ProcessStatus == DC21X4_TXM_PROCESS_SUSPENDED) && (DescOwnership == DESC_OWNED_BY_DC21X4)) { + + // Requeue the Txm packet +#if __DBG + DbgPrint(" Txm Underrun: Retry = %d\n",Adapter->UnderrunRetryCount); +#endif + //Stop the transmitter + + DC21X4_WRITE_PORT( + DC21X4_OPERATION_MODE, + Adapter->OperationMode & ~(DC21X4_TXM_START) + ); + + //Reinitialize the descriptor's ownership bits + + //First segment descriptor + Descptr = CurrentDescriptor->DescPointer; + + DC21X4_WRITE_PORT( + DC21X4_TXM_DESC_RING, + Descptr->DescriptorPa + ); + + while (TRUE) { + + Descptr->Status = DESC_OWNED_BY_DC21X4; + if (Descptr == CurrentDescriptor) { + break; + } + else { + Descptr = Descptr->Next; + } + } + + Adapter->DisableTransmitPolling = FALSE; + + //Restart the transmitter + + DC21X4_WRITE_PORT( + DC21X4_OPERATION_MODE, + Adapter->OperationMode + ); + + Adapter->UnderrunRetryCount++; + + return CurrentDescriptor; + } + else { + Adapter->DisableTransmitPolling = FALSE; + + } + + } + + Adapter->UnderrunRetryCount = 0 ; + + // Point to the first segment descriptor and walk down the descriptors + // mapping the current frame to free the physical mapping table + + Descptr = CurrentDescriptor->DescPointer; + + while (TRUE) { + + // If this descriptor points the first segment of a Ndis Buffer, free the + // Physical Mapping table of this buffer + + for (MapPtr = Descptr->MapTableIndex; + MapPtr < Descptr->MapTableIndex + NUMBER_OF_SEGMENT_PER_DESC; + MapPtr++) { + + if (Adapter->PhysicalMapping[MapPtr].Valid) { +#if _DBG + DbgPrint(" NdisMCompleteBufferPhysicalMapping (%d)\n",MapPtr); +#endif + NdisMCompleteBufferPhysicalMapping( + Adapter->MiniportAdapterHandle, + Adapter->PhysicalMapping[MapPtr].Buffer, + Adapter->PhysicalMapping[MapPtr].Register + ); + + Adapter->PhysicalMapping[MapPtr].Valid = FALSE; + MapRegistersCount++; + } + } + + if (Descptr == CurrentDescriptor) { + break; + } + else { + TxmDescriptorCount++; + Descptr = Descptr->Next; + } + + } + + // If this packet was copied into a preallocated Txm Buffer, + // free the resources + + if (CurrentDescriptor->SendStatus == CopyMaxBuffer) { + MaxTransmitBufferCount++; + } + else if (CurrentDescriptor->SendStatus == CopyMinBuffer) { + MinTransmitBufferCount++; + } + + // Update the statistics based on the Transmit status + + if (!(CurrentDescriptor->Status & Adapter->TransmitDescriptorErrorMask)) { + + // The frame was transmitted correctly + + Collisions = (CurrentDescriptor->Status & DC21X4_TDES_COLLISION_COUNT) + >> TDES_COLLISION_COUNT_BIT_NUMBER; + + if (Collisions == 1) { + Adapter->MediaMandatory[MM_TRANSMIT_ONE_COLLISION]++; + } + else if (Collisions > 1) { + Adapter->MediaMandatory[MM_TRANSMIT_MULT_COLLISIONS]++; + } + if (CurrentDescriptor->Status & DC21X4_TDES_DEFERRED) { + Adapter->MediaOptional[MO_TRANSMIT_DEFERRED]++; + } + if (CurrentDescriptor->Status & DC21X4_TDES_HEARTBEAT_FAIL) { + Adapter->MediaOptional[MO_TRANSMIT_HEARTBEAT_FAILURE]++; + } + + Adapter->GeneralOptionalCount[CurrentDescriptor->PacketType].FrameCount++; + ADD_ULONG_TO_LARGE_INTEGER( + Adapter->GeneralOptionalCount[CurrentDescriptor->PacketType].ByteCount, + CurrentDescriptor->PacketSize + ); + + Adapter->GeneralMandatory[GM_TRANSMIT_OK]++; + NdisStatus = NDIS_STATUS_SUCCESS; + } + + else { + +#if _DBG + DbgPrint("Transmit_error: DescStatus = %08x\n",CurrentDescriptor->Status); +#endif + if (CurrentDescriptor->Status & DC21X4_TDES_TXM_JABBER_TIMEOUT) { + + // This indicates a severe SIA hardware error. Stop the adapter + // to avoid generating noise on the net +#if __DBG + DbgPrint("DC21X4 TXM JABBER TIMEOUT!!!\n"); +#endif + DC21X4StopAdapter(Adapter); + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 1, + DC21X4_ERRMSG_TXM_JABBER_TIMEOUT + ); + } + + if (CurrentDescriptor->Status & DC21X4_TDES_EXCESSIVE_COLLISIONS) { +#if _DBG + DbgPrint(" Txm Excess Collisions\n"); +#endif + Adapter->MediaOptional[MO_TRANSMIT_EXC_COLLISIONS]++; + Adapter->ExcessCollisionsCount++; + } + else { + Adapter->ExcessCollisionsCount=0; + } + + if (CurrentDescriptor->Status & DC21X4_TDES_UNDERRUN_ERROR) { + + Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN]++; +#if __DBG + DbgPrint(" Txm Underrun [UnderrunCount=%d]\n",Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN]); +#endif + + if ( (Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN] >= Adapter->UnderrunThreshold) + && !(Adapter->OperationMode & DC21X4_STORE_AND_FORWARD) + ) { + + //Force StoreAndForward mode +#if __DBG + DbgPrint("UnderrunCount=%d : Force StoreAnd Forward mode\n", + Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN]); +#endif + DC21X4StopReceiverAndTransmitter(Adapter); + + Adapter->OperationMode |= DC21X4_STORE_AND_FORWARD; + + DC21X4_WRITE_PORT( + DC21X4_OPERATION_MODE, + Adapter->OperationMode + ); + } + + } + else if (CurrentDescriptor->Status & DC21X4_TDES_LATE_COLLISION) { +#if _DBG + DbgPrint(" Txm Late Collision\n"); +#endif + Adapter->MediaOptional[MO_TRANSMIT_LATE_COLLISION]++; + } + if (CurrentDescriptor->Status & DC21X4_TDES_NO_CARRIER) { +#if _DBG + DbgPrint(" Txm No Carrier\n"); +#endif + Adapter->NoCarrierCount++; + } + else { + Adapter->NoCarrierCount=0; + } + + Adapter->GeneralMandatory[GM_TRANSMIT_ERROR]++; + NdisStatus = NDIS_STATUS_FAILURE; + + } + + GoTransmitCount++; + +// if (CurrentDescriptor->SendStatus == MappedBuffer) { +#if _DBG + DbgPrint(" Signal Tx Completion desc= %08x\n", CurrentDescriptor); +#endif + NdisMSendComplete( + Adapter->MiniportAdapterHandle, + CurrentDescriptor->Packet, + NdisStatus + ); + +// } + + TxmDescriptorCount++; + Adapter->DequeueTransmitDescriptor = CurrentDescriptor->Next; + } + + else if (CurrentDescriptor->Control & DC21X4_TDES_FIRST_SEGMENT) { + +#if _DBG + DbgPrint("Int: TxmDesc %08x - First segment desc.\n",CurrentDescriptor); +#endif + Adapter->DequeueTransmitDescriptor = CurrentDescriptor->DescPointer; + + } + + else { + + TxmDescriptorCount++; + Adapter->DequeueTransmitDescriptor = CurrentDescriptor->Next; + } + + } + + if (Adapter->FullDuplex) { + NdisDprAcquireSpinLock(&Adapter->FullDuplexSpinLock); + } + + Adapter->FreeTransmitDescriptorCount += TxmDescriptorCount; + + Adapter->FreeMapRegisters += MapRegistersCount; + + Adapter->MaxTransmitBufferInUse -= MaxTransmitBufferCount; + + Adapter->MinTransmitBufferInUse -= MinTransmitBufferCount; + + Adapter->GeneralOptional[GO_TRANSMIT_QUEUE_LENGTH] -= GoTransmitCount; + + if (Adapter->FullDuplex) { + NdisDprReleaseSpinLock(&Adapter->FullDuplexSpinLock); + } + + return Adapter->DequeueTransmitDescriptor; + +} + +/*+ + * + * DC21X4EnableInterrupt + * +-*/ +extern +VOID +DC21X4EnableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ) +{ + PDC21X4_ADAPTER Adapter; + + Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; + + DC21X4_WRITE_PORT( + DC21X4_INTERRUPT_MASK, + Adapter->InterruptMask + ); + return; +} + +/*+ + * + * DC21X4DisableInterrupt + * +-*/ +extern +VOID +DC21X4DisableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ) +{ + PDC21X4_ADAPTER Adapter; + + Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; + + DC21X4_WRITE_PORT( + DC21X4_INTERRUPT_MASK, + 0 + ); + return; +} + + +/*+ + * + *DC21X4ReturnPacket + * + * Routine Description: + * + * Place a buufer released by the binding back into its free list + * + * Arguments: + * + * Return Value: + * +-*/ +NDIS_STATUS +DC21X4ReturnPacket( + IN NDIS_HANDLE MiniportAdapterContext, + IN PNDIS_PACKET Packet + ) + +{ + + PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; + PRCV_HEADER RcvHeader; + + + // Get a pointer to the receive header. + + RcvHeader = RCV_RESERVED(Packet)->RcvHeader; + ASSERT(RcvHeader->Signature == 'dHxR'); + + DC21X4LogPacket(Packet, RcvHeader, '+', (ULONG)-1); + + + // Adjust the buffer length. + + NdisAdjustBufferLength( + RcvHeader->FlushBuffer, + DC21X4_RECEIVE_BUFFER_SIZE + ); + + // Place the buffer back on the free queue. + + RcvHeader->Next = Adapter->FreeRcvList; + Adapter->FreeRcvList = RcvHeader; + + return NDIS_STATUS_SUCCESS; + +} + |