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