reactos/drivers/network/dd/e1000/interrupt.c
Dmitry Borisov 3f97671319
[E1000] Minor improvements (#3904)
- Add support for 64-bit counters (Intel gigabit NICs)
- Properly handle OIDs
- Check that the packet filter is not 0
- Performance increase
2021-12-14 01:57:33 +03:00

197 lines
6.5 KiB
C

/*
* PROJECT: ReactOS Intel PRO/1000 Driver
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Interrupt handlers
* COPYRIGHT: 2013 Cameron Gutman (cameron.gutman@reactos.org)
* 2018 Mark Jansen (mark.jansen@reactos.org)
* 2019 Victor Pereertkin (victor.perevertkin@reactos.org)
*/
#include "nic.h"
#include <debug.h>
VOID
NTAPI
MiniportISR(
OUT PBOOLEAN InterruptRecognized,
OUT PBOOLEAN QueueMiniportHandleInterrupt,
IN NDIS_HANDLE MiniportAdapterContext)
{
ULONG Value;
PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
/* Reading the interrupt acknowledges them */
E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
Value &= Adapter->InterruptMask;
_InterlockedOr(&Adapter->InterruptPending, Value);
if (Value)
{
*InterruptRecognized = TRUE;
/* Mark the events pending service */
*QueueMiniportHandleInterrupt = TRUE;
}
else
{
/* This is not ours. */
*InterruptRecognized = FALSE;
*QueueMiniportHandleInterrupt = FALSE;
}
}
VOID
NTAPI
MiniportHandleInterrupt(
IN NDIS_HANDLE MiniportAdapterContext)
{
ULONG InterruptPending;
PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor;
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
InterruptPending = _InterlockedExchange(&Adapter->InterruptPending, 0);
/* Link State Changed */
if (InterruptPending & E1000_IMS_LSC)
{
ULONG Status;
InterruptPending &= ~E1000_IMS_LSC;
NDIS_DbgPrint(MAX_TRACE, ("Link status changed!.\n"));
NICUpdateLinkStatus(Adapter);
Status = Adapter->MediaState == NdisMediaStateConnected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT;
NdisMIndicateStatus(Adapter->AdapterHandle, Status, NULL, 0);
NdisMIndicateStatusComplete(Adapter->AdapterHandle);
}
/* Handling receive interrupts */
if (InterruptPending & (E1000_IMS_RXDMT0 | E1000_IMS_RXT0))
{
volatile PE1000_RECEIVE_DESCRIPTOR ReceiveDescriptor;
PETH_HEADER EthHeader;
ULONG BufferOffset;
BOOLEAN bGotAny = FALSE;
ULONG RxDescHead, RxDescTail, CurrRxDesc;
/* Clear out these interrupts */
InterruptPending &= ~(E1000_IMS_RXDMT0 | E1000_IMS_RXT0);
E1000ReadUlong(Adapter, E1000_REG_RDH, &RxDescHead);
E1000ReadUlong(Adapter, E1000_REG_RDT, &RxDescTail);
while (((RxDescTail + 1) % NUM_RECEIVE_DESCRIPTORS) != RxDescHead)
{
CurrRxDesc = (RxDescTail + 1) % NUM_RECEIVE_DESCRIPTORS;
BufferOffset = CurrRxDesc * Adapter->ReceiveBufferEntrySize;
ReceiveDescriptor = Adapter->ReceiveDescriptors + CurrRxDesc;
/* Check if the hardware have released this descriptor (DD - Descriptor Done) */
if (!(ReceiveDescriptor->Status & E1000_RDESC_STATUS_DD))
{
/* No need to check descriptors after the first unfinished one */
break;
}
/* Ignoring these flags for now */
ReceiveDescriptor->Status &= ~(E1000_RDESC_STATUS_IXSM | E1000_RDESC_STATUS_PIF);
if (ReceiveDescriptor->Status != (E1000_RDESC_STATUS_EOP | E1000_RDESC_STATUS_DD))
{
NDIS_DbgPrint(MIN_TRACE, ("Unrecognized ReceiveDescriptor status flag: %u\n", ReceiveDescriptor->Status));
}
/* Make sure the receive indications are enabled */
if (!Adapter->PacketFilter)
{
goto NextReceiveDescriptor;
}
if (ReceiveDescriptor->Length != 0 && ReceiveDescriptor->Address != 0)
{
EthHeader = (PETH_HEADER)(Adapter->ReceiveBuffer + BufferOffset);
NdisMEthIndicateReceive(Adapter->AdapterHandle,
NULL,
(PCHAR)EthHeader,
sizeof(ETH_HEADER),
(PCHAR)(EthHeader + 1),
ReceiveDescriptor->Length - sizeof(ETH_HEADER),
ReceiveDescriptor->Length - sizeof(ETH_HEADER));
bGotAny = TRUE;
}
else
{
NDIS_DbgPrint(MIN_TRACE, ("Got a NULL descriptor"));
}
NextReceiveDescriptor:
/* Give the descriptor back */
ReceiveDescriptor->Status = 0;
RxDescTail = CurrRxDesc;
}
if (bGotAny)
{
/* Write back new tail value */
E1000WriteUlong(Adapter, E1000_REG_RDT, RxDescTail);
NDIS_DbgPrint(MAX_TRACE, ("Rx done (RDH: %u, RDT: %u)\n", RxDescHead, RxDescTail));
NdisMEthIndicateReceiveComplete(Adapter->AdapterHandle);
}
}
/* Handling transmit interrupts */
if (InterruptPending & (E1000_IMS_TXD_LOW | E1000_IMS_TXDW | E1000_IMS_TXQE))
{
PNDIS_PACKET AckPackets[40] = {0};
ULONG NumPackets = 0, i;
/* Clear out these interrupts */
InterruptPending &= ~(E1000_IMS_TXD_LOW | E1000_IMS_TXDW | E1000_IMS_TXQE);
while ((Adapter->TxFull || Adapter->LastTxDesc != Adapter->CurrentTxDesc) && NumPackets < ARRAYSIZE(AckPackets))
{
TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->LastTxDesc;
if (TransmitDescriptor->Status & E1000_TDESC_STATUS_DD)
{
if (Adapter->TransmitPackets[Adapter->LastTxDesc])
{
AckPackets[NumPackets++] = Adapter->TransmitPackets[Adapter->LastTxDesc];
Adapter->TransmitPackets[Adapter->LastTxDesc] = NULL;
TransmitDescriptor->Status = 0;
}
Adapter->LastTxDesc = (Adapter->LastTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS;
Adapter->TxFull = FALSE;
}
else
{
break;
}
}
if (NumPackets)
{
NDIS_DbgPrint(MAX_TRACE, ("Tx: (TDH: %u, TDT: %u)\n", Adapter->CurrentTxDesc, Adapter->LastTxDesc));
NDIS_DbgPrint(MAX_TRACE, ("Tx Done: %u packets to ack\n", NumPackets));
for (i = 0; i < NumPackets; ++i)
{
NdisMSendComplete(Adapter->AdapterHandle, AckPackets[i], NDIS_STATUS_SUCCESS);
}
}
}
ASSERT(InterruptPending == 0);
}