1727 lines
44 KiB
C
1727 lines
44 KiB
C
|
/*+
|
|||
|
* 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;
|
|||
|
|
|||
|
}
|
|||
|
|