[E1000] Initial send implementation.
[reactos.git] / drivers / network / dd / e1000 / interrupt.c
1 /*
2 * PROJECT: ReactOS Intel PRO/1000 Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Interrupt handlers
5 * COPYRIGHT: Copyright 2013 Cameron Gutman (cameron.gutman@reactos.org)
6 * Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
7 */
8
9 #include "nic.h"
10
11 #include <debug.h>
12
13 VOID
14 NTAPI
15 MiniportISR(
16 OUT PBOOLEAN InterruptRecognized,
17 OUT PBOOLEAN QueueMiniportHandleInterrupt,
18 IN NDIS_HANDLE MiniportAdapterContext)
19 {
20 ULONG Value;
21 PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
22
23 Value = NICInterruptRecognized(Adapter, InterruptRecognized);
24 InterlockedOr(&Adapter->InterruptPending, Value);
25
26 if (!(*InterruptRecognized))
27 {
28 /* This is not ours. */
29 *QueueMiniportHandleInterrupt = FALSE;
30 return;
31 }
32
33 /* Mark the events pending service */
34 *QueueMiniportHandleInterrupt = TRUE;
35 }
36
37 VOID
38 NTAPI
39 MiniportHandleInterrupt(
40 IN NDIS_HANDLE MiniportAdapterContext)
41 {
42 ULONG Value;
43 PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
44 volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor;
45
46 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
47
48 Value = InterlockedExchange(&Adapter->InterruptPending, 0);
49
50 NdisDprAcquireSpinLock(&Adapter->Lock);
51
52 if (Value & E1000_IMS_LSC)
53 {
54 ULONG Status;
55
56 NdisDprReleaseSpinLock(&Adapter->Lock);
57 Value &= ~E1000_IMS_LSC;
58 NDIS_DbgPrint(MIN_TRACE, ("Link status changed!.\n"));
59
60 NICUpdateLinkStatus(Adapter);
61
62 Status = Adapter->MediaState == NdisMediaStateConnected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT;
63 NdisMIndicateStatus(Adapter->AdapterHandle, Status, NULL, 0);
64 NdisMIndicateStatusComplete(Adapter->AdapterHandle);
65
66 NdisDprAcquireSpinLock(&Adapter->Lock);
67 }
68
69 if (Value & E1000_IMS_TXDW)
70 {
71 while (Adapter->TxFull || Adapter->LastTxDesc != Adapter->CurrentTxDesc)
72 {
73 TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->LastTxDesc;
74
75 if (!(TransmitDescriptor->Status & E1000_TDESC_STATUS_DD))
76 {
77 /* Not processed yet */
78 break;
79 }
80
81 Adapter->LastTxDesc = (Adapter->LastTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS;
82 Value &= ~E1000_IMS_TXDW;
83 Adapter->TxFull = FALSE;
84 NDIS_DbgPrint(MAX_TRACE, ("CurrentTxDesc:%u, LastTxDesc:%u\n", Adapter->CurrentTxDesc, Adapter->LastTxDesc));
85 }
86 }
87
88 if (Value & (E1000_IMS_RXDMT0 | E1000_IMS_RXT0))
89 {
90 volatile PE1000_RECEIVE_DESCRIPTOR ReceiveDescriptor;
91 PETH_HEADER EthHeader;
92 ULONG BufferOffset;
93
94 /* Clear out these interrupts */
95 Value &= ~(E1000_IMS_RXDMT0 | E1000_IMS_RXT0);
96
97 while (TRUE)
98 {
99 BufferOffset = Adapter->CurrentRxDesc * Adapter->ReceiveBufferEntrySize;
100 ReceiveDescriptor = Adapter->ReceiveDescriptors + Adapter->CurrentRxDesc;
101
102 if (!(ReceiveDescriptor->Status & E1000_RDESC_STATUS_DD))
103 {
104 /* Not received yet */
105 break;
106 }
107
108 if (ReceiveDescriptor->Length != 0)
109 {
110 EthHeader = Adapter->ReceiveBuffer + BufferOffset;
111
112 NdisMEthIndicateReceive(Adapter->AdapterHandle,
113 NULL,
114 EthHeader,
115 sizeof(ETH_HEADER),
116 EthHeader + 1,
117 ReceiveDescriptor->Length - sizeof(ETH_HEADER),
118 ReceiveDescriptor->Length - sizeof(ETH_HEADER));
119
120 if (ReceiveDescriptor->Status & E1000_RDESC_STATUS_EOP)
121 {
122 NdisMEthIndicateReceiveComplete(Adapter->AdapterHandle);
123 }
124 else
125 {
126 __debugbreak();
127 }
128 }
129
130 /* Restore the descriptor Address, incase we received a NULL descriptor */
131 ReceiveDescriptor->Address = Adapter->ReceiveBufferPa.QuadPart + BufferOffset;
132 /* Give the descriptor back */
133 ReceiveDescriptor->Status = 0;
134 E1000WriteUlong(Adapter, E1000_REG_RDT, Adapter->CurrentRxDesc);
135 Adapter->CurrentRxDesc = (Adapter->CurrentRxDesc + 1) % NUM_RECEIVE_DESCRIPTORS;
136 }
137 }
138
139 ASSERT(Value == 0);
140 }