mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
3f97671319
- Add support for 64-bit counters (Intel gigabit NICs) - Properly handle OIDs - Check that the packet filter is not 0 - Performance increase
197 lines
6.5 KiB
C
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);
|
|
}
|