[E1000] Initial send implementation.
authorMark Jansen <mark.jansen@reactos.org>
Sun, 3 Jun 2018 20:43:50 +0000 (22:43 +0200)
committerMark Jansen <mark.jansen@reactos.org>
Thu, 7 Feb 2019 18:48:54 +0000 (19:48 +0100)
CORE-14675

drivers/network/dd/e1000/e1000hw.h
drivers/network/dd/e1000/hardware.c
drivers/network/dd/e1000/interrupt.c
drivers/network/dd/e1000/nic.h

index 2ee4893..b2293aa 100644 (file)
@@ -31,6 +31,22 @@ typedef struct _ETH_HEADER {
 
 
 
+typedef enum _E1000_RCVBUF_SIZE
+{
+    E1000_RCVBUF_2048 = 0,
+    E1000_RCVBUF_1024 = 1,
+    E1000_RCVBUF_512 = 2,
+    E1000_RCVBUF_256 = 3,
+
+    E1000_RCVBUF_INDEXMASK = 3,
+    E1000_RCVBUF_RESERVED = 4 | 0,
+
+    E1000_RCVBUF_16384 = 4 | 1,
+    E1000_RCVBUF_8192 =  4 | 2,
+    E1000_RCVBUF_4096 =  4 | 3,
+} E1000_RCVBUF_SIZE;
+
+
 
 #include <pshpack1.h>
 
@@ -95,13 +111,20 @@ C_ASSERT(sizeof(E1000_TRANSMIT_DESCRIPTOR) == 16);
 #define E1000_REG_MDIC              0x0020      /* MDI Control Register, R/W */
 #define E1000_REG_VET               0x0038      /* VLAN Ether Type, R/W */
 #define E1000_REG_ICR               0x00C0      /* Interrupt Cause Read, R/clr */
+#define E1000_REG_ITR               0x00C4      /* Interrupt Throttling Register, R/W */
 
 #define E1000_REG_IMS               0x00D0      /* Interrupt Mask Set/Read Register, R/W */
 #define E1000_REG_IMC               0x00D8      /* Interrupt Mask Clear, W */
-#define E1000_REG_RCTL              0x0100      /* Receive Control Register, R/W */
 
+#define E1000_REG_RCTL              0x0100      /* Receive Control Register, R/W */
 #define E1000_REG_TCTL              0x0400      /* Transmit Control Register, R/W */
 
+#define E1000_REG_RDBAL             0x2800      /* Receive Descriptor Base Address Low, R/W */
+#define E1000_REG_RDBAH             0x2804      /* Receive Descriptor Base Address High, R/W */
+#define E1000_REG_RDLEN             0x2808      /* Receive Descriptor Length, R/W */
+#define E1000_REG_RDH               0x2810      /* Receive Descriptor Head, R/W */
+#define E1000_REG_RDT               0x2818      /* Receive Descriptor Tail, R/W */
+
 #define E1000_REG_TDBAL             0x3800      /* Transmit Descriptor Base Address Low, R/W */
 #define E1000_REG_TDBAH             0x3804      /* Transmit Descriptor Base Address High, R/W */
 #define E1000_REG_TDLEN             0x3808      /* Transmit Descriptor Length, R/W */
@@ -142,6 +165,13 @@ C_ASSERT(sizeof(E1000_TRANSMIT_DESCRIPTOR) == 16);
 /* E1000_REG_IMS */
 #define E1000_IMS_TXDW              (1 << 0)    /* Transmit Descriptor Written Back */
 #define E1000_IMS_LSC               (1 << 2)    /* Sets mask for Link Status Change */
+#define E1000_IMS_RXDMT0            (1 << 4)    /* Receive Descriptor Minimum Threshold Reached */
+#define E1000_IMS_RXT0              (1 << 7)    /* Receiver Timer Interrupt */
+
+
+/* E1000_REG_ITR */
+#define MAX_INTS_PER_SEC        2000
+#define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
 
 
 /* E1000_REG_RCTL */
@@ -150,7 +180,10 @@ C_ASSERT(sizeof(E1000_TRANSMIT_DESCRIPTOR) == 16);
 #define E1000_RCTL_UPE              (1 << 3)    /* Unicast Promiscuous Enabled */
 #define E1000_RCTL_MPE              (1 << 4)    /* Multicast Promiscuous Enabled */
 #define E1000_RCTL_BAM              (1 << 15)   /* Broadcast Accept Mode */
+#define E1000_RCTL_BSIZE_SHIFT      16
 #define E1000_RCTL_PMCF             (1 << 23)   /* Pass MAC Control Frames */
+#define E1000_RCTL_BSEX             (1 << 25)   /* Buffer Size Extension */
+#define E1000_RCTL_SECRC            (1 << 26)   /* Strip Ethernet CRC from incoming packet */
 
 #define E1000_RCTL_FILTER_BITS      (E1000_RCTL_SBP | E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_BAM | E1000_RCTL_PMCF)
 
index f510d99..0b7d8f0 100644 (file)
@@ -24,7 +24,7 @@ static ULONG E1000WriteFlush(IN PE1000_ADAPTER Adapter)
     return Value;
 }
 
-static VOID E1000WriteUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value)
+VOID NTAPI E1000WriteUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value)
 {
     NdisWriteRegisterUlong((PULONG)(Adapter->IoBase + Address), Value);
 }
@@ -41,6 +41,64 @@ static VOID E1000WriteIoUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN UL
     NdisRawWritePortUlong((PULONG)(Adapter->IoPort + 4), Value);
 }
 
+static ULONG PacketFilterToMask(ULONG PacketFilter)
+{
+    ULONG FilterMask = 0;
+
+    if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+    {
+        /* Multicast Promiscuous Enabled */
+        FilterMask |= E1000_RCTL_MPE;
+    }
+    if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+    {
+        /* Unicast Promiscuous Enabled */
+        FilterMask |= E1000_RCTL_UPE;
+        /* Multicast Promiscuous Enabled */
+        FilterMask |= E1000_RCTL_MPE;
+    }
+    if (PacketFilter & NDIS_PACKET_TYPE_MAC_FRAME)
+    {
+        /* Pass MAC Control Frames */
+        FilterMask |= E1000_RCTL_PMCF;
+    }
+    if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
+    {
+        /* Broadcast Accept Mode */
+        FilterMask |= E1000_RCTL_BAM;
+    }
+
+    return FilterMask;
+}
+
+static ULONG RcvBufAllocationSize(E1000_RCVBUF_SIZE BufSize)
+{
+    static ULONG PredefSizes[4] = {
+        2048, 1024, 512, 256,
+    };
+    ULONG Size;
+
+    Size = PredefSizes[BufSize & E1000_RCVBUF_INDEXMASK];
+    if (BufSize & E1000_RCVBUF_RESERVED)
+    {
+        ASSERT(BufSize != 2048);
+        Size *= 16;
+    }
+    return Size;
+}
+
+static ULONG RcvBufRegisterMask(E1000_RCVBUF_SIZE BufSize)
+{
+    ULONG Mask = 0;
+
+    Mask |= BufSize & E1000_RCVBUF_INDEXMASK;
+    Mask <<= E1000_RCTL_BSIZE_SHIFT;
+    if (BufSize & E1000_RCVBUF_RESERVED)
+        Mask |= E1000_RCTL_BSEX;
+
+    return Mask;
+}
+
 static BOOLEAN E1000ReadMdic(IN PE1000_ADAPTER Adapter, IN ULONG Address, USHORT *Result)
 {
     ULONG ResultAddress;
@@ -242,6 +300,9 @@ NICAllocateIoResources(
     IN PE1000_ADAPTER Adapter)
 {
     NDIS_STATUS Status;
+    ULONG AllocationSize;
+    UINT n;
+
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
     Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->IoPort,
@@ -271,6 +332,47 @@ NICAllocateIoResources(
         return NDIS_STATUS_RESOURCES;
     }
 
+    for (n = 0; n < NUM_TRANSMIT_DESCRIPTORS; ++n)
+    {
+        PE1000_TRANSMIT_DESCRIPTOR Descriptor = Adapter->TransmitDescriptors + n;
+        Descriptor->Address = 0;
+        Descriptor->Length = 0;
+    }
+
+    NdisMAllocateSharedMemory(Adapter->AdapterHandle,
+                              sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS,
+                              FALSE,
+                              (PVOID*)&Adapter->ReceiveDescriptors,
+                              &Adapter->ReceiveDescriptorsPa);
+    if (Adapter->ReceiveDescriptors == NULL)
+    {
+        NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive descriptors\n"));
+        return NDIS_STATUS_RESOURCES;
+    }
+
+    AllocationSize = RcvBufAllocationSize(Adapter->ReceiveBufferType);
+    ASSERT(Adapter->ReceiveBufferEntrySize == 0 || Adapter->ReceiveBufferEntrySize == AllocationSize);
+    Adapter->ReceiveBufferEntrySize = AllocationSize;
+
+    NdisMAllocateSharedMemory(Adapter->AdapterHandle,
+                              Adapter->ReceiveBufferEntrySize * NUM_RECEIVE_DESCRIPTORS,
+                              FALSE,
+                              (PVOID*)&Adapter->ReceiveBuffer,
+                              &Adapter->ReceiveBufferPa);
+
+    if (Adapter->ReceiveBuffer == NULL)
+    {
+        NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive buffer\n"));
+        return NDIS_STATUS_RESOURCES;
+    }
+
+    for (n = 0; n < NUM_RECEIVE_DESCRIPTORS; ++n)
+    {
+        PE1000_RECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptors + n;
+
+        RtlZeroMemory(Descriptor, sizeof(*Descriptor));
+        Descriptor->Address = Adapter->ReceiveBufferPa.QuadPart + n * Adapter->ReceiveBufferEntrySize;
+    }
 
     return NDIS_STATUS_SUCCESS;
 }
@@ -323,11 +425,45 @@ NICReleaseIoResources(
 {
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
+    if (Adapter->ReceiveDescriptors != NULL)
+    {
+        /* Disassociate our shared buffer before freeing it to avoid NIC-induced memory corruption */
+        if (Adapter->IoBase)
+        {
+            E1000WriteUlong(Adapter, E1000_REG_RDH, 0);
+            E1000WriteUlong(Adapter, E1000_REG_RDT, 0);
+        }
+
+        NdisMFreeSharedMemory(Adapter->AdapterHandle,
+                              sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS,
+                              FALSE,
+                              Adapter->ReceiveDescriptors,
+                              Adapter->ReceiveDescriptorsPa);
+
+        Adapter->ReceiveDescriptors = NULL;
+    }
+
+    if (Adapter->ReceiveBuffer != NULL)
+    {
+        NdisMFreeSharedMemory(Adapter->AdapterHandle,
+                              Adapter->ReceiveBufferEntrySize * NUM_RECEIVE_DESCRIPTORS,
+                              FALSE,
+                              Adapter->ReceiveBuffer,
+                              Adapter->ReceiveBufferPa);
+
+        Adapter->ReceiveBuffer = NULL;
+        Adapter->ReceiveBufferEntrySize = 0;
+    }
+
+
     if (Adapter->TransmitDescriptors != NULL)
     {
         /* Disassociate our shared buffer before freeing it to avoid NIC-induced memory corruption */
-        //E1000WriteUlong(Adapter, E1000_REG_TDH, 0);
-        //E1000WriteUlong(Adapter, E1000_REG_TDT, 0);
+        if (Adapter->IoBase)
+        {
+            E1000WriteUlong(Adapter, E1000_REG_TDH, 0);
+            E1000WriteUlong(Adapter, E1000_REG_TDT, 0);
+        }
 
         NdisMFreeSharedMemory(Adapter->AdapterHandle,
                               sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS,
@@ -429,6 +565,10 @@ NICEnableTxRx(
     ULONG Value;
 
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+    NDIS_DbgPrint(MID_TRACE, ("Setting up transmit.\n"));
+
+    /* Make sure the thing is disabled first. */
+    E1000WriteUlong(Adapter, E1000_REG_TCTL, 0);
 
     /* Transmit descriptor ring buffer */
     E1000WriteUlong(Adapter, E1000_REG_TDBAH, Adapter->TransmitDescriptorsPa.HighPart);
@@ -447,12 +587,36 @@ NICEnableTxRx(
     E1000WriteUlong(Adapter, E1000_REG_TCTL, Value);
 
 
+    NDIS_DbgPrint(MID_TRACE, ("Setting up receive.\n"));
+
+    /* Make sure the thing is disabled first. */
+    E1000WriteUlong(Adapter, E1000_REG_RCTL, 0);
 
+    /* Receive descriptor ring buffer */
+    E1000WriteUlong(Adapter, E1000_REG_RDBAH, Adapter->ReceiveDescriptorsPa.HighPart);
+    E1000WriteUlong(Adapter, E1000_REG_RDBAL, Adapter->ReceiveDescriptorsPa.LowPart);
 
-    //E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value);
-    //Value = E1000_RCTL_BSIZE_2048 | E1000_RCTL_SECRC | E1000_RCTL_EN;
-    //E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
+    /* Receive descriptor buffer size */
+    E1000WriteUlong(Adapter, E1000_REG_RDLEN, sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS);
 
+    /* Receive descriptor tail / head */
+    E1000WriteUlong(Adapter, E1000_REG_RDH, 0);
+    E1000WriteUlong(Adapter, E1000_REG_RDT, NUM_RECEIVE_DESCRIPTORS - 1);
+    Adapter->CurrentRxDesc = 0;
+
+    /* Setup Interrupt Throttling */
+    E1000WriteUlong(Adapter, E1000_REG_ITR, DEFAULT_ITR);
+
+    /* Some defaults */
+    Value = E1000_RCTL_SECRC | E1000_RCTL_EN;
+
+    /* Receive buffer size */
+    Value |= RcvBufRegisterMask(Adapter->ReceiveBufferType);
+
+    /* Add our current packet filter */
+    Value |= PacketFilterToMask(Adapter->PacketFilter);
+
+    E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
 
     return NDIS_STATUS_SUCCESS;
 }
@@ -542,35 +706,12 @@ NTAPI
 NICApplyPacketFilter(
     IN PE1000_ADAPTER Adapter)
 {
-    ULONG FilterMask = 0;
+    ULONG FilterMask;
 
     E1000ReadUlong(Adapter, E1000_REG_RCTL, &FilterMask);
 
     FilterMask &= ~E1000_RCTL_FILTER_BITS;
-
-    if (Adapter->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
-    {
-        /* Multicast Promiscuous Enabled */
-        FilterMask |= E1000_RCTL_MPE;
-    }
-    if (Adapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
-    {
-        /* Unicast Promiscuous Enabled */
-        FilterMask |= E1000_RCTL_UPE;
-        /* Multicast Promiscuous Enabled */
-        FilterMask |= E1000_RCTL_MPE;
-    }
-    if (Adapter->PacketFilter & NDIS_PACKET_TYPE_MAC_FRAME)
-    {
-        /* Pass MAC Control Frames */
-        FilterMask |= E1000_RCTL_PMCF;
-    }
-    if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
-    {
-        /* Broadcast Accept Mode */
-        FilterMask |= E1000_RCTL_BAM;
-    }
-
+    FilterMask |= PacketFilterToMask(Adapter->PacketFilter);
     E1000WriteUlong(Adapter, E1000_REG_RCTL, FilterMask);
 
     return NDIS_STATUS_SUCCESS;
index c651962..cd94e45 100644 (file)
@@ -52,6 +52,7 @@ MiniportHandleInterrupt(
     if (Value & E1000_IMS_LSC)
     {
         ULONG Status;
+
         NdisDprReleaseSpinLock(&Adapter->Lock);
         Value &= ~E1000_IMS_LSC;
         NDIS_DbgPrint(MIN_TRACE, ("Link status changed!.\n"));
@@ -84,6 +85,56 @@ MiniportHandleInterrupt(
         }
     }
 
+    if (Value & (E1000_IMS_RXDMT0 | E1000_IMS_RXT0))
+    {
+        volatile PE1000_RECEIVE_DESCRIPTOR ReceiveDescriptor;
+        PETH_HEADER EthHeader;
+        ULONG BufferOffset;
+
+        /* Clear out these interrupts */
+        Value &= ~(E1000_IMS_RXDMT0 | E1000_IMS_RXT0);
+
+        while (TRUE)
+        {
+            BufferOffset = Adapter->CurrentRxDesc * Adapter->ReceiveBufferEntrySize;
+            ReceiveDescriptor = Adapter->ReceiveDescriptors + Adapter->CurrentRxDesc;
+
+            if (!(ReceiveDescriptor->Status & E1000_RDESC_STATUS_DD))
+            {
+                /* Not received yet */
+                break;
+            }
+
+            if (ReceiveDescriptor->Length != 0)
+            {
+                EthHeader = Adapter->ReceiveBuffer + BufferOffset;
+
+                NdisMEthIndicateReceive(Adapter->AdapterHandle,
+                                        NULL,
+                                        EthHeader,
+                                        sizeof(ETH_HEADER),
+                                        EthHeader + 1,
+                                        ReceiveDescriptor->Length - sizeof(ETH_HEADER),
+                                        ReceiveDescriptor->Length - sizeof(ETH_HEADER));
+
+                if (ReceiveDescriptor->Status & E1000_RDESC_STATUS_EOP)
+                {
+                    NdisMEthIndicateReceiveComplete(Adapter->AdapterHandle);
+                }
+                else
+                {
+                    __debugbreak();
+                }
+            }
+
+            /* 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;
+        }
+    }
 
     ASSERT(Value == 0);
 }
index 7b42d05..be19870 100644 (file)
@@ -21,7 +21,7 @@
 #define DRIVER_VERSION 1
 
 
-#define DEFAULT_INTERRUPT_MASK      (E1000_IMS_LSC | E1000_IMS_TXDW)
+#define DEFAULT_INTERRUPT_MASK      (E1000_IMS_LSC | E1000_IMS_TXDW | E1000_IMS_RXDMT0 | E1000_IMS_RXT0)
 
 typedef struct _E1000_ADAPTER
 {
@@ -72,6 +72,18 @@ typedef struct _E1000_ADAPTER
     ULONG LastTxDesc;
     BOOLEAN TxFull;
 
+
+    /* Receive */
+    PE1000_RECEIVE_DESCRIPTOR ReceiveDescriptors;
+    NDIS_PHYSICAL_ADDRESS ReceiveDescriptorsPa;
+
+    ULONG CurrentRxDesc;
+
+    E1000_RCVBUF_SIZE ReceiveBufferType;
+    volatile PUCHAR ReceiveBuffer;
+    NDIS_PHYSICAL_ADDRESS ReceiveBufferPa;
+    ULONG ReceiveBufferEntrySize;
+
 } E1000_ADAPTER, *PE1000_ADAPTER;
 
 
@@ -202,4 +214,14 @@ NTAPI
 MiniportHandleInterrupt(
     IN NDIS_HANDLE MiniportAdapterContext);
 
+
+VOID
+NTAPI
+E1000WriteUlong(
+    IN PE1000_ADAPTER Adapter,
+    IN ULONG Address,
+    IN ULONG Value);
+
+
+
 #endif /* _E1000_PCH_ */