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