mirror of
https://github.com/reactos/reactos.git
synced 2024-11-10 00:34:39 +00:00
626 lines
16 KiB
C
626 lines
16 KiB
C
|
/*
|
||
|
* PROJECT: ReactOS DC21x4 Driver
|
||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||
|
* PURPOSE: Interrupt handling
|
||
|
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
|
||
|
*/
|
||
|
|
||
|
/* INCLUDES *******************************************************************/
|
||
|
|
||
|
#include "dc21x4.h"
|
||
|
|
||
|
#include <debug.h>
|
||
|
|
||
|
/* FUNCTIONS ******************************************************************/
|
||
|
|
||
|
static
|
||
|
VOID
|
||
|
DcAdjustTxFifoThreshold(
|
||
|
_In_ PDC21X4_ADAPTER Adapter)
|
||
|
{
|
||
|
ULONG OpMode;
|
||
|
|
||
|
TRACE("TX underrun\n");
|
||
|
|
||
|
/* Maximum threshold reached */
|
||
|
if ((Adapter->OpMode & DC_OPMODE_STORE_AND_FORWARD) ||
|
||
|
(++Adapter->TransmitUnderruns < DC_TX_UNDERRUN_LIMIT))
|
||
|
{
|
||
|
NdisDprAcquireSpinLock(&Adapter->SendLock);
|
||
|
|
||
|
/* Start the transmit process if it was suspended */
|
||
|
DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
|
||
|
|
||
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
||
|
return;
|
||
|
}
|
||
|
Adapter->TransmitUnderruns = 0;
|
||
|
|
||
|
NdisDprAcquireSpinLock(&Adapter->ModeLock);
|
||
|
|
||
|
OpMode = Adapter->OpMode;
|
||
|
|
||
|
/* Update the FIFO threshold level to minimize Tx FIFO underrun */
|
||
|
if ((OpMode & DC_OPMODE_TX_THRESHOLD_CTRL_MASK) != DC_OPMODE_TX_THRESHOLD_MAX)
|
||
|
{
|
||
|
OpMode += DC_OPMODE_TX_THRESHOLD_LEVEL;
|
||
|
|
||
|
INFO("New OP Mode %08lx\n", OpMode);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OpMode |= DC_OPMODE_STORE_AND_FORWARD;
|
||
|
|
||
|
INFO("Store & Forward\n");
|
||
|
}
|
||
|
|
||
|
DcStopTxRxProcess(Adapter);
|
||
|
|
||
|
Adapter->OpMode = OpMode;
|
||
|
|
||
|
/* Restart the transmit process */
|
||
|
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
|
||
|
|
||
|
NdisDprReleaseSpinLock(&Adapter->ModeLock);
|
||
|
}
|
||
|
|
||
|
static
|
||
|
VOID
|
||
|
DcHandleTxJabberTimeout(
|
||
|
_In_ PDC21X4_ADAPTER Adapter)
|
||
|
{
|
||
|
WARN("Transmit jabber timer timed out\n");
|
||
|
|
||
|
NdisWriteErrorLogEntry(Adapter->AdapterHandle, NDIS_ERROR_CODE_HARDWARE_FAILURE, 1, __LINE__);
|
||
|
|
||
|
NdisDprAcquireSpinLock(&Adapter->ModeLock);
|
||
|
|
||
|
/* Start the transmit process if it was stopped */
|
||
|
DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
|
||
|
|
||
|
NdisDprReleaseSpinLock(&Adapter->ModeLock);
|
||
|
}
|
||
|
|
||
|
static
|
||
|
VOID
|
||
|
DcHandleTxCompletedFrames(
|
||
|
_In_ PDC21X4_ADAPTER Adapter,
|
||
|
_Inout_ PLIST_ENTRY SendReadyList,
|
||
|
_Out_ PULONG DpcEvents)
|
||
|
{
|
||
|
PDC_TCB Tcb;
|
||
|
PDC_TBD Tbd;
|
||
|
ULONG TbdStatus, Collisions;
|
||
|
|
||
|
for (Tcb = Adapter->LastTcb;
|
||
|
Tcb != Adapter->CurrentTcb;
|
||
|
Tcb = DC_NEXT_TCB(Adapter, Tcb))
|
||
|
{
|
||
|
Tbd = Tcb->Tbd;
|
||
|
TbdStatus = Tbd->Status;
|
||
|
|
||
|
if (TbdStatus & DC_TBD_STATUS_OWNED)
|
||
|
break;
|
||
|
|
||
|
++Adapter->TcbCompleted;
|
||
|
|
||
|
/* Complete the packet filter change request asynchronously */
|
||
|
if (Tbd->Control & DC_TBD_CONTROL_SETUP_FRAME)
|
||
|
{
|
||
|
Tbd->Control &= ~DC_TBD_CONTROL_SETUP_FRAME;
|
||
|
|
||
|
if (Tbd->Control & DC_TBD_CONTROL_REQUEST_INTERRUPT)
|
||
|
{
|
||
|
*DpcEvents |= DC_EVENT_SETUP_FRAME_COMPLETED;
|
||
|
}
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* This is our media test packet, so no need to update the TX statistics */
|
||
|
if (!Tcb->Packet)
|
||
|
{
|
||
|
_InterlockedExchange(&Adapter->MediaTestStatus,
|
||
|
!(TbdStatus & DC_TBD_STATUS_ERROR_SUMMARY));
|
||
|
|
||
|
ASSERT(Adapter->LoopbackFrameSlots < DC_LOOPBACK_FRAMES);
|
||
|
|
||
|
++Adapter->LoopbackFrameSlots;
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (TbdStatus & DC_TBD_STATUS_ERROR_SUMMARY)
|
||
|
{
|
||
|
++Adapter->Statistics.TransmitErrors;
|
||
|
|
||
|
if (TbdStatus & DC_TBD_STATUS_UNDERFLOW)
|
||
|
++Adapter->Statistics.TransmitUnderrunErrors;
|
||
|
else if (TbdStatus & DC_TBD_STATUS_LATE_COLLISION)
|
||
|
++Adapter->Statistics.TransmitLateCollisions;
|
||
|
|
||
|
if (TbdStatus & DC_TBD_STATUS_RETRY_ERROR)
|
||
|
++Adapter->Statistics.TransmitExcessiveCollisions;
|
||
|
if (TbdStatus & DC_TBD_STATUS_CARRIER_LOST)
|
||
|
++Adapter->Statistics.TransmitLostCarrierSense;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
++Adapter->Statistics.TransmitOk;
|
||
|
|
||
|
if (TbdStatus & DC_TBD_STATUS_DEFFERED)
|
||
|
++Adapter->Statistics.TransmitDeferred;
|
||
|
if (TbdStatus & DC_TBD_STATUS_HEARTBEAT_FAIL)
|
||
|
++Adapter->Statistics.TransmitHeartbeatErrors;
|
||
|
|
||
|
Collisions = (TbdStatus & DC_TBD_STATUS_COLLISIONS_MASK) >>
|
||
|
DC_TBD_STATUS_COLLISIONS_SHIFT;
|
||
|
if (Collisions == 1)
|
||
|
++Adapter->Statistics.TransmitOneRetry;
|
||
|
else if (Collisions > 1)
|
||
|
++Adapter->Statistics.TransmitMoreCollisions;
|
||
|
}
|
||
|
|
||
|
InsertTailList(SendReadyList, DC_LIST_ENTRY_FROM_PACKET(Tcb->Packet));
|
||
|
|
||
|
DC_RELEASE_TCB(Adapter, Tcb);
|
||
|
}
|
||
|
|
||
|
Adapter->LastTcb = Tcb;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
VOID
|
||
|
DcHandleTx(
|
||
|
_In_ PDC21X4_ADAPTER Adapter)
|
||
|
{
|
||
|
LIST_ENTRY SendReadyList;
|
||
|
ULONG DpcEvents;
|
||
|
|
||
|
TRACE("Handle TX\n");
|
||
|
|
||
|
InitializeListHead(&SendReadyList);
|
||
|
DpcEvents = 0;
|
||
|
|
||
|
NdisDprAcquireSpinLock(&Adapter->SendLock);
|
||
|
|
||
|
DcHandleTxCompletedFrames(Adapter, &SendReadyList, &DpcEvents);
|
||
|
|
||
|
if (!IsListEmpty(&Adapter->SendQueueList))
|
||
|
{
|
||
|
DcProcessPendingPackets(Adapter);
|
||
|
}
|
||
|
|
||
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
||
|
|
||
|
while (!IsListEmpty(&SendReadyList))
|
||
|
{
|
||
|
PLIST_ENTRY Entry = RemoveHeadList(&SendReadyList);
|
||
|
|
||
|
TRACE("Complete TX packet %p\n", DC_PACKET_FROM_LIST_ENTRY(Entry));
|
||
|
|
||
|
NdisMSendComplete(Adapter->AdapterHandle,
|
||
|
DC_PACKET_FROM_LIST_ENTRY(Entry),
|
||
|
NDIS_STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
/* We have to complete the OID request outside of the spinlock */
|
||
|
if (DpcEvents & DC_EVENT_SETUP_FRAME_COMPLETED)
|
||
|
{
|
||
|
TRACE("SP completed\n");
|
||
|
|
||
|
Adapter->OidPending = FALSE;
|
||
|
|
||
|
NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static
|
||
|
VOID
|
||
|
DcStopRxProcess(
|
||
|
_In_ PDC21X4_ADAPTER Adapter)
|
||
|
{
|
||
|
ULONG i, OpMode, Status;
|
||
|
|
||
|
OpMode = Adapter->OpMode;
|
||
|
OpMode &= ~DC_OPMODE_RX_ENABLE;
|
||
|
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
|
||
|
|
||
|
for (i = 0; i < 5000; ++i)
|
||
|
{
|
||
|
Status = DC_READ(Adapter, DcCsr5_Status);
|
||
|
|
||
|
if ((Status & DC_STATUS_RX_STATE_MASK) == DC_STATUS_RX_STATE_STOPPED)
|
||
|
return;
|
||
|
|
||
|
NdisStallExecution(10);
|
||
|
}
|
||
|
|
||
|
WARN("Failed to stop the RX process 0x%08lx\n", Status);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
NTAPI
|
||
|
DcReturnPacket(
|
||
|
_In_ NDIS_HANDLE MiniportAdapterContext,
|
||
|
_In_ PNDIS_PACKET Packet)
|
||
|
{
|
||
|
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
|
||
|
PDC_RCB Rcb;
|
||
|
|
||
|
Rcb = *DC_RCB_FROM_PACKET(Packet);
|
||
|
|
||
|
NdisAcquireSpinLock(&Adapter->ReceiveLock);
|
||
|
|
||
|
PushEntryList(&Adapter->FreeRcbList, &Rcb->ListEntry);
|
||
|
|
||
|
++Adapter->RcbFree;
|
||
|
|
||
|
NdisReleaseSpinLock(&Adapter->ReceiveLock);
|
||
|
}
|
||
|
|
||
|
static
|
||
|
VOID
|
||
|
DcIndicateReceivePackets(
|
||
|
_In_ PDC21X4_ADAPTER Adapter,
|
||
|
_In_ PNDIS_PACKET* ReceiveArray,
|
||
|
_In_ ULONG PacketsToIndicate)
|
||
|
{
|
||
|
PNDIS_PACKET Packet;
|
||
|
PDC_RBD Rbd;
|
||
|
PDC_RCB Rcb;
|
||
|
ULONG i;
|
||
|
|
||
|
NdisDprReleaseSpinLock(&Adapter->ReceiveLock);
|
||
|
|
||
|
NdisMIndicateReceivePacket(Adapter->AdapterHandle,
|
||
|
ReceiveArray,
|
||
|
PacketsToIndicate);
|
||
|
|
||
|
NdisDprAcquireSpinLock(&Adapter->ReceiveLock);
|
||
|
|
||
|
for (i = 0; i < PacketsToIndicate; ++i)
|
||
|
{
|
||
|
Packet = ReceiveArray[i];
|
||
|
Rcb = *DC_RCB_FROM_PACKET(Packet);
|
||
|
|
||
|
/* Reuse the RCB immediately */
|
||
|
if (Rcb->Flags & DC_RCB_FLAG_RECLAIM)
|
||
|
{
|
||
|
Rbd = *DC_RBD_FROM_PACKET(Packet);
|
||
|
|
||
|
Rbd->Status = DC_RBD_STATUS_OWNED;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static
|
||
|
VOID
|
||
|
DcHandleRxReceivedFrames(
|
||
|
_In_ PDC21X4_ADAPTER Adapter)
|
||
|
{
|
||
|
PDC_RBD Rbd, StartRbd, LastRbd;
|
||
|
ULONG PacketsToIndicate;
|
||
|
PNDIS_PACKET ReceiveArray[DC_RECEIVE_ARRAY_SIZE];
|
||
|
|
||
|
Rbd = StartRbd = LastRbd = Adapter->CurrentRbd;
|
||
|
PacketsToIndicate = 0;
|
||
|
|
||
|
while (PacketsToIndicate < RTL_NUMBER_OF(ReceiveArray))
|
||
|
{
|
||
|
PDC_RCB Rcb;
|
||
|
PDC_RCB* RcbSlot;
|
||
|
PNDIS_PACKET Packet;
|
||
|
ULONG RbdStatus, PacketLength, RxCounters;
|
||
|
|
||
|
if (Rbd->Status & DC_RBD_STATUS_OWNED)
|
||
|
break;
|
||
|
|
||
|
/* Work around the RX overflow bug */
|
||
|
if ((Adapter->Features & DC_NEED_RX_OVERFLOW_WORKAROUND) && (Rbd == LastRbd))
|
||
|
{
|
||
|
/* Find the last received packet, to correctly catch invalid packets */
|
||
|
do
|
||
|
{
|
||
|
LastRbd = DC_NEXT_RBD(Adapter, LastRbd);
|
||
|
|
||
|
if (LastRbd->Status & DC_RBD_STATUS_OWNED)
|
||
|
break;
|
||
|
}
|
||
|
while (LastRbd != Rbd);
|
||
|
|
||
|
RxCounters = DC_READ(Adapter, DcCsr8_RxCounters);
|
||
|
|
||
|
Adapter->Statistics.ReceiveNoBuffers += RxCounters & DC_COUNTER_RX_NO_BUFFER_MASK;
|
||
|
|
||
|
/* A receive overflow might indicate a data corruption */
|
||
|
if (RxCounters & DC_COUNTER_RX_OVERFLOW_MASK)
|
||
|
{
|
||
|
ERR("RX overflow, dropping the packets\n");
|
||
|
|
||
|
Adapter->Statistics.ReceiveOverrunErrors +=
|
||
|
(RxCounters & DC_COUNTER_RX_OVERFLOW_MASK) >> DC_COUNTER_RX_OVERFLOW_SHIFT;
|
||
|
|
||
|
NdisDprAcquireSpinLock(&Adapter->ModeLock);
|
||
|
|
||
|
/* Stop the receive process */
|
||
|
DcStopRxProcess(Adapter);
|
||
|
|
||
|
/* Drop all received packets regardless of what the status indicates */
|
||
|
while (TRUE)
|
||
|
{
|
||
|
if (Rbd->Status & DC_RBD_STATUS_OWNED)
|
||
|
break;
|
||
|
|
||
|
++Adapter->Statistics.ReceiveOverrunErrors;
|
||
|
|
||
|
Rbd->Status = DC_RBD_STATUS_OWNED;
|
||
|
|
||
|
Rbd = DC_NEXT_RBD(Adapter, Rbd);
|
||
|
}
|
||
|
LastRbd = Rbd;
|
||
|
|
||
|
/* Restart the receive process */
|
||
|
DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
|
||
|
|
||
|
NdisDprReleaseSpinLock(&Adapter->ModeLock);
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RbdStatus = Rbd->Status;
|
||
|
|
||
|
/* Ignore oversized packets */
|
||
|
if (!(RbdStatus & DC_RBD_STATUS_LAST_DESCRIPTOR))
|
||
|
{
|
||
|
Rbd->Status = DC_RBD_STATUS_OWNED;
|
||
|
goto NextRbd;
|
||
|
}
|
||
|
|
||
|
/* Check for an invalid packet */
|
||
|
if (RbdStatus & DC_RBD_STATUS_INVALID)
|
||
|
{
|
||
|
++Adapter->Statistics.ReceiveErrors;
|
||
|
|
||
|
if (RbdStatus & DC_RBD_STATUS_OVERRUN)
|
||
|
++Adapter->Statistics.ReceiveOverrunErrors;
|
||
|
|
||
|
if (RbdStatus & DC_RBD_STATUS_CRC_ERROR)
|
||
|
{
|
||
|
if (RbdStatus & DC_RBD_STATUS_DRIBBLE)
|
||
|
++Adapter->Statistics.ReceiveAlignmentErrors;
|
||
|
else
|
||
|
++Adapter->Statistics.ReceiveCrcErrors;
|
||
|
}
|
||
|
|
||
|
Rbd->Status = DC_RBD_STATUS_OWNED;
|
||
|
goto NextRbd;
|
||
|
}
|
||
|
|
||
|
++Adapter->Statistics.ReceiveOk;
|
||
|
|
||
|
PacketLength = (RbdStatus & DC_RBD_STATUS_FRAME_LENGTH_MASK) >>
|
||
|
DC_RBD_STATUS_FRAME_LENGTH_SHIFT;
|
||
|
|
||
|
/* Omit the CRC */
|
||
|
PacketLength -= 4;
|
||
|
|
||
|
RcbSlot = DC_GET_RCB_SLOT(Adapter, Rbd);
|
||
|
Rcb = *RcbSlot;
|
||
|
|
||
|
TRACE("RX packet (len %u), RCB %p\n", PacketLength, Rcb);
|
||
|
|
||
|
NdisAdjustBufferLength(Rcb->NdisBuffer, PacketLength);
|
||
|
|
||
|
/* Receive buffers are in cached memory */
|
||
|
NdisFlushBuffer(Rcb->NdisBuffer, FALSE);
|
||
|
|
||
|
if (RbdStatus & DC_RBD_STATUS_MULTICAST)
|
||
|
{
|
||
|
if (ETH_IS_BROADCAST(Rcb->VirtualAddress))
|
||
|
++Adapter->Statistics.ReceiveBroadcast;
|
||
|
else
|
||
|
++Adapter->Statistics.ReceiveMulticast;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
++Adapter->Statistics.ReceiveUnicast;
|
||
|
}
|
||
|
|
||
|
Packet = Rcb->Packet;
|
||
|
|
||
|
ReceiveArray[PacketsToIndicate++] = Packet;
|
||
|
|
||
|
if (Adapter->FreeRcbList.Next)
|
||
|
{
|
||
|
Rcb->Flags = 0;
|
||
|
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
|
||
|
|
||
|
Rcb = (PDC_RCB)DcPopEntryList(&Adapter->FreeRcbList);
|
||
|
*RcbSlot = Rcb;
|
||
|
|
||
|
ASSERT(Adapter->RcbFree > 0);
|
||
|
--Adapter->RcbFree;
|
||
|
|
||
|
Rbd->Address1 = Rcb->PhysicalAddress;
|
||
|
DC_WRITE_BARRIER();
|
||
|
Rbd->Status = DC_RBD_STATUS_OWNED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Rcb->Flags = DC_RCB_FLAG_RECLAIM;
|
||
|
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
|
||
|
|
||
|
*DC_RBD_FROM_PACKET(Packet) = Rbd;
|
||
|
}
|
||
|
|
||
|
NextRbd:
|
||
|
Rbd = DC_NEXT_RBD(Adapter, Rbd);
|
||
|
|
||
|
/*
|
||
|
* Check the next descriptor to prevent wrap-around.
|
||
|
* Since we don't use a fixed-sized ring,
|
||
|
* the receive ring may be smaller in length than the ReceiveArray[].
|
||
|
*/
|
||
|
if (Rbd == StartRbd)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Adapter->CurrentRbd = Rbd;
|
||
|
|
||
|
/* Pass the packets up */
|
||
|
if (PacketsToIndicate)
|
||
|
{
|
||
|
DcIndicateReceivePackets(Adapter, ReceiveArray, PacketsToIndicate);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static
|
||
|
VOID
|
||
|
DcHandleRx(
|
||
|
_In_ PDC21X4_ADAPTER Adapter)
|
||
|
{
|
||
|
NdisDprAcquireSpinLock(&Adapter->ReceiveLock);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
DcHandleRxReceivedFrames(Adapter);
|
||
|
}
|
||
|
while (!(Adapter->CurrentRbd->Status & DC_RBD_STATUS_OWNED));
|
||
|
|
||
|
NdisDprReleaseSpinLock(&Adapter->ReceiveLock);
|
||
|
}
|
||
|
|
||
|
static
|
||
|
VOID
|
||
|
DcHandleSystemError(
|
||
|
_In_ PDC21X4_ADAPTER Adapter,
|
||
|
_In_ ULONG InterruptStatus)
|
||
|
{
|
||
|
ERR("%s error occured, CSR5 %08lx\n", DcDbgBusError(InterruptStatus), InterruptStatus);
|
||
|
|
||
|
NdisWriteErrorLogEntry(Adapter->AdapterHandle, NDIS_ERROR_CODE_HARDWARE_FAILURE, 1, __LINE__);
|
||
|
|
||
|
/* Issue a software reset, which also enables the interrupts */
|
||
|
if (_InterlockedCompareExchange(&Adapter->ResetLock, 2, 0) == 0)
|
||
|
{
|
||
|
NdisScheduleWorkItem(&Adapter->ResetWorkItem);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
NTAPI
|
||
|
DcHandleInterrupt(
|
||
|
_In_ NDIS_HANDLE MiniportAdapterContext)
|
||
|
{
|
||
|
ULONG InterruptStatus, IoLimit;
|
||
|
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
|
||
|
|
||
|
TRACE("Events %08lx\n", Adapter->InterruptStatus);
|
||
|
|
||
|
if (!(Adapter->Flags & DC_ACTIVE))
|
||
|
return;
|
||
|
|
||
|
IoLimit = DC_INTERRUPT_PROCESSING_LIMIT;
|
||
|
InterruptStatus = Adapter->InterruptStatus;
|
||
|
|
||
|
/* Loop until the condition to stop is encountered */
|
||
|
while (TRUE)
|
||
|
{
|
||
|
/* Uncommon interrupts */
|
||
|
if (InterruptStatus & DC_IRQ_ABNORMAL_SUMMARY)
|
||
|
{
|
||
|
/* PCI bus error detected */
|
||
|
if (InterruptStatus & DC_IRQ_SYSTEM_ERROR)
|
||
|
{
|
||
|
DcHandleSystemError(Adapter, InterruptStatus);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Transmit jabber timeout */
|
||
|
if (InterruptStatus & DC_IRQ_TX_JABBER_TIMEOUT)
|
||
|
{
|
||
|
DcHandleTxJabberTimeout(Adapter);
|
||
|
}
|
||
|
|
||
|
/* Link state changed */
|
||
|
if (InterruptStatus & Adapter->LinkStateChangeMask)
|
||
|
{
|
||
|
Adapter->HandleLinkStateChange(Adapter, InterruptStatus);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Handling receive interrupts */
|
||
|
if (InterruptStatus & (DC_IRQ_RX_OK | DC_IRQ_RX_STOPPED))
|
||
|
{
|
||
|
DcHandleRx(Adapter);
|
||
|
}
|
||
|
|
||
|
/* Handling transmit interrupts */
|
||
|
if (InterruptStatus & (DC_IRQ_TX_OK | DC_IRQ_TX_STOPPED))
|
||
|
{
|
||
|
DcHandleTx(Adapter);
|
||
|
}
|
||
|
|
||
|
/* Transmit underflow error detected */
|
||
|
if (InterruptStatus & DC_IRQ_TX_UNDERFLOW)
|
||
|
{
|
||
|
DcAdjustTxFifoThreshold(Adapter);
|
||
|
}
|
||
|
|
||
|
/* Limit in order to avoid doing too much work at DPC level */
|
||
|
if (!--IoLimit)
|
||
|
break;
|
||
|
|
||
|
/* Check if new events have occurred */
|
||
|
InterruptStatus = DC_READ(Adapter, DcCsr5_Status);
|
||
|
if (InterruptStatus == 0xFFFFFFFF || !(InterruptStatus & Adapter->InterruptMask))
|
||
|
break;
|
||
|
|
||
|
/* Acknowledge the events */
|
||
|
DC_WRITE(Adapter, DcCsr5_Status, InterruptStatus);
|
||
|
}
|
||
|
|
||
|
/* TODO: Add interrupt mitigation (CSR11) */
|
||
|
|
||
|
/* Reenable interrupts */
|
||
|
_InterlockedExchange((PLONG)&Adapter->CurrentInterruptMask, Adapter->InterruptMask);
|
||
|
DC_WRITE(Adapter, DcCsr7_IrqMask, Adapter->InterruptMask);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
NTAPI
|
||
|
DcIsr(
|
||
|
_Out_ PBOOLEAN InterruptRecognized,
|
||
|
_Out_ PBOOLEAN QueueMiniportHandleInterrupt,
|
||
|
_In_ NDIS_HANDLE MiniportAdapterContext)
|
||
|
{
|
||
|
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
|
||
|
ULONG InterruptStatus;
|
||
|
|
||
|
if (Adapter->CurrentInterruptMask == 0)
|
||
|
goto NotOurs;
|
||
|
|
||
|
InterruptStatus = DC_READ(Adapter, DcCsr5_Status);
|
||
|
if (InterruptStatus == 0xFFFFFFFF || !(InterruptStatus & Adapter->CurrentInterruptMask))
|
||
|
goto NotOurs;
|
||
|
|
||
|
/* Disable further interrupts */
|
||
|
DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
|
||
|
|
||
|
/* Clear all pending events */
|
||
|
DC_WRITE(Adapter, DcCsr5_Status, InterruptStatus);
|
||
|
|
||
|
Adapter->InterruptStatus = InterruptStatus;
|
||
|
Adapter->CurrentInterruptMask = 0;
|
||
|
|
||
|
*InterruptRecognized = TRUE;
|
||
|
*QueueMiniportHandleInterrupt = TRUE;
|
||
|
return;
|
||
|
|
||
|
NotOurs:
|
||
|
*InterruptRecognized = FALSE;
|
||
|
*QueueMiniportHandleInterrupt = FALSE;
|
||
|
}
|