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;
|
||
|
||
}
|
||
|