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