xref: /reactos/drivers/network/dd/e1000/interrupt.c (revision 84344399)
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:   2013 Cameron Gutman (cameron.gutman@reactos.org)
6  *              2018 Mark Jansen (mark.jansen@reactos.org)
7  *              2019 Victor Pereertkin (victor.perevertkin@reactos.org)
8  */
9 
10 #include "nic.h"
11 
12 #include <debug.h>
13 
14 VOID
15 NTAPI
16 MiniportISR(
17     OUT PBOOLEAN InterruptRecognized,
18     OUT PBOOLEAN QueueMiniportHandleInterrupt,
19     IN NDIS_HANDLE MiniportAdapterContext)
20 {
21     ULONG Value;
22     PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
23 
24     /* Reading the interrupt acknowledges them */
25     E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
26 
27     Value &= Adapter->InterruptMask;
28     _InterlockedOr(&Adapter->InterruptPending, Value);
29 
30     if (Value)
31     {
32         *InterruptRecognized = TRUE;
33         /* Mark the events pending service */
34         *QueueMiniportHandleInterrupt = TRUE;
35     }
36     else
37     {
38         /* This is not ours. */
39         *InterruptRecognized = FALSE;
40         *QueueMiniportHandleInterrupt = FALSE;
41     }
42 }
43 
44 VOID
45 NTAPI
46 MiniportHandleInterrupt(
47     IN NDIS_HANDLE MiniportAdapterContext)
48 {
49     ULONG InterruptPending;
50     PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
51     volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor;
52 
53     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
54 
55     InterruptPending = _InterlockedExchange(&Adapter->InterruptPending, 0);
56 
57 
58     /* Link State Changed */
59     if (InterruptPending & E1000_IMS_LSC)
60     {
61         ULONG Status;
62 
63         InterruptPending &= ~E1000_IMS_LSC;
64         NDIS_DbgPrint(MAX_TRACE, ("Link status changed!.\n"));
65 
66         NICUpdateLinkStatus(Adapter);
67 
68         Status = Adapter->MediaState == NdisMediaStateConnected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT;
69 
70         NdisMIndicateStatus(Adapter->AdapterHandle, Status, NULL, 0);
71         NdisMIndicateStatusComplete(Adapter->AdapterHandle);
72     }
73 
74     /* Handling receive interrupts */
75     if (InterruptPending & (E1000_IMS_RXDMT0 | E1000_IMS_RXT0))
76     {
77         volatile PE1000_RECEIVE_DESCRIPTOR ReceiveDescriptor;
78         PETH_HEADER EthHeader;
79         ULONG BufferOffset;
80         BOOLEAN bGotAny = FALSE;
81         ULONG RxDescHead, RxDescTail, CurrRxDesc;
82 
83         /* Clear out these interrupts */
84         InterruptPending &= ~(E1000_IMS_RXDMT0 | E1000_IMS_RXT0);
85 
86         E1000ReadUlong(Adapter, E1000_REG_RDH, &RxDescHead);
87         E1000ReadUlong(Adapter, E1000_REG_RDT, &RxDescTail);
88 
89         while (((RxDescTail + 1) % NUM_RECEIVE_DESCRIPTORS) != RxDescHead)
90         {
91             CurrRxDesc = (RxDescTail + 1) % NUM_RECEIVE_DESCRIPTORS;
92             BufferOffset = CurrRxDesc * Adapter->ReceiveBufferEntrySize;
93             ReceiveDescriptor = Adapter->ReceiveDescriptors + CurrRxDesc;
94 
95             /* Check if the hardware have released this descriptor (DD - Descriptor Done) */
96             if (!(ReceiveDescriptor->Status & E1000_RDESC_STATUS_DD))
97             {
98                 /* No need to check descriptors after the first unfinished one */
99                 break;
100             }
101 
102             /* Ignoring these flags for now */
103             ReceiveDescriptor->Status &= ~(E1000_RDESC_STATUS_IXSM | E1000_RDESC_STATUS_PIF);
104 
105             if (ReceiveDescriptor->Status != (E1000_RDESC_STATUS_EOP | E1000_RDESC_STATUS_DD))
106             {
107                 NDIS_DbgPrint(MIN_TRACE, ("Unrecognized ReceiveDescriptor status flag: %u\n", ReceiveDescriptor->Status));
108             }
109 
110             /* Make sure the receive indications are enabled */
111             if (!Adapter->PacketFilter)
112             {
113                 goto NextReceiveDescriptor;
114             }
115 
116             if (ReceiveDescriptor->Length != 0 && ReceiveDescriptor->Address != 0)
117             {
118                 EthHeader = (PETH_HEADER)(Adapter->ReceiveBuffer + BufferOffset);
119 
120                 NdisMEthIndicateReceive(Adapter->AdapterHandle,
121                                         NULL,
122                                         (PCHAR)EthHeader,
123                                         sizeof(ETH_HEADER),
124                                         (PCHAR)(EthHeader + 1),
125                                         ReceiveDescriptor->Length - sizeof(ETH_HEADER),
126                                         ReceiveDescriptor->Length - sizeof(ETH_HEADER));
127 
128                 bGotAny = TRUE;
129             }
130             else
131             {
132                 NDIS_DbgPrint(MIN_TRACE, ("Got a NULL descriptor"));
133             }
134 
135 NextReceiveDescriptor:
136             /* Give the descriptor back */
137             ReceiveDescriptor->Status = 0;
138 
139             RxDescTail = CurrRxDesc;
140         }
141 
142         if (bGotAny)
143         {
144             /* Write back new tail value */
145             E1000WriteUlong(Adapter, E1000_REG_RDT, RxDescTail);
146 
147             NDIS_DbgPrint(MAX_TRACE, ("Rx done (RDH: %u, RDT: %u)\n", RxDescHead, RxDescTail));
148 
149             NdisMEthIndicateReceiveComplete(Adapter->AdapterHandle);
150         }
151     }
152 
153     /* Handling transmit interrupts */
154     if (InterruptPending & (E1000_IMS_TXD_LOW | E1000_IMS_TXDW | E1000_IMS_TXQE))
155     {
156         PNDIS_PACKET AckPackets[40] = {0};
157         ULONG NumPackets = 0, i;
158 
159         /* Clear out these interrupts */
160         InterruptPending &= ~(E1000_IMS_TXD_LOW | E1000_IMS_TXDW | E1000_IMS_TXQE);
161 
162         while ((Adapter->TxFull || Adapter->LastTxDesc != Adapter->CurrentTxDesc) && NumPackets < ARRAYSIZE(AckPackets))
163         {
164             TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->LastTxDesc;
165 
166             if (TransmitDescriptor->Status & E1000_TDESC_STATUS_DD)
167             {
168                 if (Adapter->TransmitPackets[Adapter->LastTxDesc])
169                 {
170                     AckPackets[NumPackets++] = Adapter->TransmitPackets[Adapter->LastTxDesc];
171                     Adapter->TransmitPackets[Adapter->LastTxDesc] = NULL;
172                     TransmitDescriptor->Status = 0;
173                 }
174 
175                 Adapter->LastTxDesc = (Adapter->LastTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS;
176                 Adapter->TxFull = FALSE;
177             }
178             else
179             {
180                 break;
181             }
182         }
183 
184         if (NumPackets)
185         {
186             NDIS_DbgPrint(MAX_TRACE, ("Tx: (TDH: %u, TDT: %u)\n", Adapter->CurrentTxDesc, Adapter->LastTxDesc));
187             NDIS_DbgPrint(MAX_TRACE, ("Tx Done: %u packets to ack\n", NumPackets));
188 
189             for (i = 0; i < NumPackets; ++i)
190             {
191                 NdisMSendComplete(Adapter->AdapterHandle, AckPackets[i], NDIS_STATUS_SUCCESS);
192             }
193         }
194     }
195 
196     ASSERT(InterruptPending == 0);
197 }
198