[E1000] Finished an implementation of the driver.
[reactos.git] / drivers / network / dd / e1000 / interrupt.c
index cd94e45..e3f1b83 100644 (file)
@@ -2,8 +2,9 @@
  * PROJECT:     ReactOS Intel PRO/1000 Driver
  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
  * PURPOSE:     Interrupt handlers
- * COPYRIGHT:   Copyright 2013 Cameron Gutman (cameron.gutman@reactos.org)
- *              Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
+ * COPYRIGHT:   2013 Cameron Gutman (cameron.gutman@reactos.org)
+ *              2018 Mark Jansen (mark.jansen@reactos.org)
+ *              2019 Victor Pereertkin (victor.perevertkin@reactos.org)
  */
 
 #include "nic.h"
@@ -39,102 +40,145 @@ NTAPI
 MiniportHandleInterrupt(
     IN NDIS_HANDLE MiniportAdapterContext)
 {
-    ULONG Value;
+    ULONG InterruptPending;
     PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
     volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor;
 
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
-    Value = InterlockedExchange(&Adapter->InterruptPending, 0);
+    InterruptPending = InterlockedExchange(&Adapter->InterruptPending, 0);
 
-    NdisDprAcquireSpinLock(&Adapter->Lock);
 
-    if (Value & E1000_IMS_LSC)
+    /* Link State Changed */
+    if (InterruptPending & E1000_IMS_LSC)
     {
         ULONG Status;
 
-        NdisDprReleaseSpinLock(&Adapter->Lock);
-        Value &= ~E1000_IMS_LSC;
-        NDIS_DbgPrint(MIN_TRACE, ("Link status changed!.\n"));
+        InterruptPending &= ~E1000_IMS_LSC;
+        NDIS_DbgPrint(MAX_TRACE, ("Link status changed!.\n"));
 
         NICUpdateLinkStatus(Adapter);
 
         Status = Adapter->MediaState == NdisMediaStateConnected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT;
+
         NdisMIndicateStatus(Adapter->AdapterHandle, Status, NULL, 0);
         NdisMIndicateStatusComplete(Adapter->AdapterHandle);
-
-        NdisDprAcquireSpinLock(&Adapter->Lock);
-    }
-
-    if (Value & E1000_IMS_TXDW)
-    {
-        while (Adapter->TxFull || Adapter->LastTxDesc != Adapter->CurrentTxDesc)
-        {
-            TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->LastTxDesc;
-
-            if (!(TransmitDescriptor->Status & E1000_TDESC_STATUS_DD))
-            {
-                /* Not processed yet */
-                break;
-            }
-
-            Adapter->LastTxDesc = (Adapter->LastTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS;
-            Value &= ~E1000_IMS_TXDW;
-            Adapter->TxFull = FALSE;
-            NDIS_DbgPrint(MAX_TRACE, ("CurrentTxDesc:%u, LastTxDesc:%u\n", Adapter->CurrentTxDesc, Adapter->LastTxDesc));
-        }
     }
 
-    if (Value & (E1000_IMS_RXDMT0 | E1000_IMS_RXT0))
+    /* Handling receive interrupts */
+    if (InterruptPending & (E1000_IMS_RXDMT0 | E1000_IMS_RXT0))
     {
         volatile PE1000_RECEIVE_DESCRIPTOR ReceiveDescriptor;
         PETH_HEADER EthHeader;
         ULONG BufferOffset;
+        BOOLEAN bGotAny = FALSE;
+        ULONG RxDescHead, RxDescTail, CurrRxDesc;
 
         /* Clear out these interrupts */
-        Value &= ~(E1000_IMS_RXDMT0 | E1000_IMS_RXT0);
+        InterruptPending &= ~(E1000_IMS_RXDMT0 | E1000_IMS_RXT0);
 
-        while (TRUE)
+        E1000ReadUlong(Adapter, E1000_REG_RDH, &RxDescHead);
+        E1000ReadUlong(Adapter, E1000_REG_RDT, &RxDescTail);
+
+        while (((RxDescTail + 1) % NUM_RECEIVE_DESCRIPTORS) != RxDescHead)
         {
-            BufferOffset = Adapter->CurrentRxDesc * Adapter->ReceiveBufferEntrySize;
-            ReceiveDescriptor = Adapter->ReceiveDescriptors + Adapter->CurrentRxDesc;
+            CurrRxDesc = (RxDescTail + 1) % NUM_RECEIVE_DESCRIPTORS;
+            BufferOffset = CurrRxDesc * Adapter->ReceiveBufferEntrySize;
+            ReceiveDescriptor = Adapter->ReceiveDescriptors + CurrRxDesc;
 
+            /* Check if the hardware have released this descriptor (DD - Descriptor Done) */
             if (!(ReceiveDescriptor->Status & E1000_RDESC_STATUS_DD))
             {
-                /* Not received yet */
+                /* No need to check descriptors after the first unfinished one */
                 break;
             }
 
-            if (ReceiveDescriptor->Length != 0)
+            /* Ignoring these flags for now */
+            ReceiveDescriptor->Status &= ~(E1000_RDESC_STATUS_IXSM | E1000_RDESC_STATUS_PIF);
+
+            if (ReceiveDescriptor->Status != (E1000_RDESC_STATUS_EOP | E1000_RDESC_STATUS_DD))
             {
-                EthHeader = Adapter->ReceiveBuffer + BufferOffset;
+                NDIS_DbgPrint(MIN_TRACE, ("Unrecognized ReceiveDescriptor status flag: %u\n", ReceiveDescriptor->Status));
+            }
+
+            if (ReceiveDescriptor->Length != 0 && ReceiveDescriptor->Address != 0)
+            {
+                EthHeader = (PETH_HEADER)(Adapter->ReceiveBuffer + BufferOffset);
 
                 NdisMEthIndicateReceive(Adapter->AdapterHandle,
                                         NULL,
-                                        EthHeader,
+                                        (PCHAR)EthHeader,
                                         sizeof(ETH_HEADER),
-                                        EthHeader + 1,
+                                        (PCHAR)(EthHeader + 1),
                                         ReceiveDescriptor->Length - sizeof(ETH_HEADER),
                                         ReceiveDescriptor->Length - sizeof(ETH_HEADER));
 
-                if (ReceiveDescriptor->Status & E1000_RDESC_STATUS_EOP)
-                {
-                    NdisMEthIndicateReceiveComplete(Adapter->AdapterHandle);
-                }
-                else
-                {
-                    __debugbreak();
-                }
+                bGotAny = TRUE;
+            }
+            else
+            {
+                NDIS_DbgPrint(MIN_TRACE, ("Got a NULL descriptor"));
             }
 
-            /* Restore the descriptor Address, incase we received a NULL descriptor */
-            ReceiveDescriptor->Address = Adapter->ReceiveBufferPa.QuadPart + BufferOffset;
             /* Give the descriptor back */
             ReceiveDescriptor->Status = 0;
-            E1000WriteUlong(Adapter, E1000_REG_RDT, Adapter->CurrentRxDesc);
-            Adapter->CurrentRxDesc = (Adapter->CurrentRxDesc + 1) % NUM_RECEIVE_DESCRIPTORS;
+
+            RxDescTail = CurrRxDesc;
+        }
+
+        if (bGotAny)
+        {
+            /* Write back new tail value */
+            E1000WriteUlong(Adapter, E1000_REG_RDT, RxDescTail);
+
+            NDIS_DbgPrint(MAX_TRACE, ("Rx done (RDH: %u, RDT: %u)\n", RxDescHead, RxDescTail));
+
+            NdisMEthIndicateReceiveComplete(Adapter->AdapterHandle);
+        }
+    }
+
+    /* Handling transmit interrupts */
+    if (InterruptPending & (E1000_IMS_TXD_LOW | E1000_IMS_TXDW | E1000_IMS_TXQE))
+    {
+        PNDIS_PACKET AckPackets[40] = {0};
+        ULONG NumPackets = 0, i;
+
+        /* Clear out these interrupts */
+        InterruptPending &= ~(E1000_IMS_TXD_LOW | E1000_IMS_TXDW | E1000_IMS_TXQE);
+
+        while ((Adapter->TxFull || Adapter->LastTxDesc != Adapter->CurrentTxDesc) && NumPackets < ARRAYSIZE(AckPackets))
+        {
+            TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->LastTxDesc;
+
+            if (TransmitDescriptor->Status & E1000_TDESC_STATUS_DD)
+            {
+                if (Adapter->TransmitPackets[Adapter->LastTxDesc])
+                {
+                    AckPackets[NumPackets++] = Adapter->TransmitPackets[Adapter->LastTxDesc];
+                    Adapter->TransmitPackets[Adapter->LastTxDesc] = NULL;
+                    TransmitDescriptor->Status = 0;
+                }
+
+                Adapter->LastTxDesc = (Adapter->LastTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS;
+                Adapter->TxFull = FALSE;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        if (NumPackets)
+        {
+            NDIS_DbgPrint(MAX_TRACE, ("Tx: (TDH: %u, TDT: %u)\n", Adapter->CurrentTxDesc, Adapter->LastTxDesc));
+            NDIS_DbgPrint(MAX_TRACE, ("Tx Done: %u packets to ack\n", NumPackets));
+
+            for (i = 0; i < NumPackets; ++i)
+            {
+                NdisMSendComplete(Adapter->AdapterHandle, AckPackets[i], NDIS_STATUS_SUCCESS);
+            }
         }
     }
 
-    ASSERT(Value == 0);
+    ASSERT(InterruptPending == 0);
 }