[E1000] Implement basic sending.
authorMark Jansen <mark.jansen@reactos.org>
Tue, 29 May 2018 20:52:43 +0000 (22:52 +0200)
committerMark Jansen <mark.jansen@reactos.org>
Thu, 7 Feb 2019 18:48:54 +0000 (19:48 +0100)
Implement some interrupt recognition

CORE-14675

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

index 9932974..2ee4893 100644 (file)
@@ -32,6 +32,61 @@ typedef struct _ETH_HEADER {
 
 
 
+#include <pshpack1.h>
+
+
+/* 3.2.3 Receive Descriptor Format */
+
+#define E1000_RDESC_STATUS_EOP          (1 << 1)    /* End of Packet */
+#define E1000_RDESC_STATUS_DD           (1 << 0)    /* Descriptor Done */
+
+typedef struct _E1000_RECEIVE_DESCRIPTOR
+{
+    UINT64 Address;
+
+    USHORT Length;
+    USHORT Checksum;
+    UCHAR Status;
+    UCHAR Errors;
+    USHORT Special;
+
+} E1000_RECEIVE_DESCRIPTOR, *PE1000_RECEIVE_DESCRIPTOR;
+
+
+/* 3.3.3 Legacy Transmit Descriptor Format */
+
+#define E1000_TDESC_CMD_RS              (1 << 3)    /* Report Status */
+#define E1000_TDESC_CMD_IFCS            (1 << 1)    /* Insert FCS */
+#define E1000_TDESC_CMD_EOP             (1 << 0)    /* End Of Packet */
+
+#define E1000_TDESC_STATUS_DD           (1 << 0)    /* Descriptor Done */
+
+typedef struct _E1000_TRANSMIT_DESCRIPTOR
+{
+    UINT64 Address;
+
+    USHORT Length;
+    UCHAR ChecksumOffset;
+    UCHAR Command;
+    UCHAR Status;
+    UCHAR ChecksumStartField;
+    USHORT Special;
+
+} E1000_TRANSMIT_DESCRIPTOR, *PE1000_TRANSMIT_DESCRIPTOR;
+
+#include <poppack.h>
+
+
+C_ASSERT(sizeof(E1000_RECEIVE_DESCRIPTOR) == 16);
+C_ASSERT(sizeof(E1000_TRANSMIT_DESCRIPTOR) == 16);
+
+
+/* Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
+   Valid Range: 80-4096 for 82544 and newer */
+#define NUM_TRANSMIT_DESCRIPTORS        128
+#define NUM_RECEIVE_DESCRIPTORS         128
+
+
 
 /* Registers */
 #define E1000_REG_CTRL              0x0000      /* Device Control Register, R/W */
@@ -43,7 +98,16 @@ typedef struct _ETH_HEADER {
 
 #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, 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_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 */
+#define E1000_REG_TDH               0x3810      /* Transmit Descriptor Head, R/W */
+#define E1000_REG_TDT               0x3818      /* Transmit Descriptor Tail, R/W */
+
 
 #define E1000_REG_RAL               0x5400      /* Receive Address Low, R/W */
 #define E1000_REG_RAH               0x5404      /* Receive Address High, R/W */
@@ -76,6 +140,7 @@ typedef struct _ETH_HEADER {
 
 
 /* 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 */
 
 
@@ -89,6 +154,14 @@ typedef struct _ETH_HEADER {
 
 #define E1000_RCTL_FILTER_BITS      (E1000_RCTL_SBP | E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_BAM | E1000_RCTL_PMCF)
 
+
+/* E1000_REG_TCTL */
+#define E1000_TCTL_EN               (1 << 1)    /* Transmit Enable */
+#define E1000_TCTL_PSP              (1 << 3)    /* Pad Short Packets */
+
+
+
+
 /* E1000_REG_RAH */
 #define E1000_RAH_AV                (1 << 31)   /* Address Valid */
 
index 5308afa..f510d99 100644 (file)
@@ -259,6 +259,19 @@ NICAllocateIoResources(
                              Adapter->IoAddress,
                              Adapter->IoLength);
 
+
+    NdisMAllocateSharedMemory(Adapter->AdapterHandle,
+                              sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS,
+                              FALSE,
+                              (PVOID*)&Adapter->TransmitDescriptors,
+                              &Adapter->TransmitDescriptorsPa);
+    if (Adapter->TransmitDescriptors == NULL)
+    {
+        NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate transmit descriptors\n"));
+        return NDIS_STATUS_RESOURCES;
+    }
+
+
     return NDIS_STATUS_SUCCESS;
 }
 
@@ -310,6 +323,23 @@ NICReleaseIoResources(
 {
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
+    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);
+
+        NdisMFreeSharedMemory(Adapter->AdapterHandle,
+                              sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS,
+                              FALSE,
+                              Adapter->TransmitDescriptors,
+                              Adapter->TransmitDescriptorsPa);
+
+        Adapter->TransmitDescriptors = NULL;
+    }
+
+
+
     if (Adapter->IoPort)
     {
         NdisMDeregisterIoPortRange(Adapter->AdapterHandle,
@@ -396,8 +426,34 @@ NTAPI
 NICEnableTxRx(
     IN PE1000_ADAPTER Adapter)
 {
+    ULONG Value;
+
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
+    /* Transmit descriptor ring buffer */
+    E1000WriteUlong(Adapter, E1000_REG_TDBAH, Adapter->TransmitDescriptorsPa.HighPart);
+    E1000WriteUlong(Adapter, E1000_REG_TDBAL, Adapter->TransmitDescriptorsPa.LowPart);
+
+    /* Transmit descriptor buffer size */
+    E1000WriteUlong(Adapter, E1000_REG_TDLEN, sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS);
+
+    /* Transmit descriptor tail / head */
+    E1000WriteUlong(Adapter, E1000_REG_TDH, 0);
+    E1000WriteUlong(Adapter, E1000_REG_TDT, 0);
+    Adapter->CurrentTxDesc = 0;
+
+
+    Value = E1000_TCTL_EN | E1000_TCTL_PSP;
+    E1000WriteUlong(Adapter, E1000_REG_TCTL, Value);
+
+
+
+
+    //E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value);
+    //Value = E1000_RCTL_BSIZE_2048 | E1000_RCTL_SECRC | E1000_RCTL_EN;
+    //E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
+
+
     return NDIS_STATUS_SUCCESS;
 }
 
@@ -406,8 +462,18 @@ NTAPI
 NICDisableTxRx(
     IN PE1000_ADAPTER Adapter)
 {
+    ULONG Value;
+
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
+    E1000ReadUlong(Adapter, E1000_REG_TCTL, &Value);
+    Value &= ~E1000_TCTL_EN;
+    E1000WriteUlong(Adapter, E1000_REG_TCTL, Value);
+
+    //E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value);
+    //Value &= ~E1000_RCTL_EN;
+    //E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
+
     return NDIS_STATUS_SUCCESS;
 }
 
@@ -532,23 +598,22 @@ NICDisableInterrupts(
     return NDIS_STATUS_SUCCESS;
 }
 
-USHORT
+ULONG
 NTAPI
 NICInterruptRecognized(
     IN PE1000_ADAPTER Adapter,
     OUT PBOOLEAN InterruptRecognized)
 {
+    ULONG Value;
+
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
-    return 0;
-}
+    /* Reading the interrupt acknowledges them */
+    E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
 
-VOID
-NTAPI
-NICAcknowledgeInterrupts(
-    IN PE1000_ADAPTER Adapter)
-{
-    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+    *InterruptRecognized = (Value & Adapter->InterruptMask) != 0;
+
+    return (Value & Adapter->InterruptMask);
 }
 
 VOID
@@ -604,11 +669,33 @@ NDIS_STATUS
 NTAPI
 NICTransmitPacket(
     IN PE1000_ADAPTER Adapter,
-    IN UCHAR TxDesc,
     IN ULONG PhysicalAddress,
     IN ULONG Length)
 {
+    volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
-    return NDIS_STATUS_FAILURE;
+    TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->CurrentTxDesc;
+    TransmitDescriptor->Address = PhysicalAddress;
+    TransmitDescriptor->Length = Length;
+    TransmitDescriptor->ChecksumOffset = 0;
+    TransmitDescriptor->Command = E1000_TDESC_CMD_RS | E1000_TDESC_CMD_IFCS | E1000_TDESC_CMD_EOP;
+    TransmitDescriptor->Status = 0;
+    TransmitDescriptor->ChecksumStartField = 0;
+    TransmitDescriptor->Special = 0;
+
+    Adapter->CurrentTxDesc = (Adapter->CurrentTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS;
+
+    E1000WriteUlong(Adapter, E1000_REG_TDT, Adapter->CurrentTxDesc);
+
+    NDIS_DbgPrint(MAX_TRACE, ("CurrentTxDesc:%u, LastTxDesc:%u\n", Adapter->CurrentTxDesc, Adapter->LastTxDesc));
+
+    if (Adapter->CurrentTxDesc == Adapter->LastTxDesc)
+    {
+        NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n"));
+        Adapter->TxFull = TRUE;
+    }
+
+    return NDIS_STATUS_SUCCESS;
 }
index 16e46e7..c651962 100644 (file)
@@ -17,15 +17,12 @@ MiniportISR(
     OUT PBOOLEAN QueueMiniportHandleInterrupt,
     IN NDIS_HANDLE MiniportAdapterContext)
 {
+    ULONG Value;
     PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
 
-    //
-    // FIXME: We need to synchronize with this ISR for changes to InterruptPending,
-    // LinkChange, MediaState, and LinkSpeedMbps. We can get away with IRQL
-    // synchronization on non-SMP machines because we run a DIRQL here.
-    //
+    Value = NICInterruptRecognized(Adapter, InterruptRecognized);
+    InterlockedOr(&Adapter->InterruptPending, Value);
 
-    Adapter->InterruptPending |= NICInterruptRecognized(Adapter, InterruptRecognized);
     if (!(*InterruptRecognized))
     {
         /* This is not ours. */
@@ -33,10 +30,7 @@ MiniportISR(
         return;
     }
 
-    UNIMPLEMENTED;
-
-    /* Acknowledge the interrupt and mark the events pending service */
-    NICAcknowledgeInterrupts(Adapter);
+    /* Mark the events pending service */
     *QueueMiniportHandleInterrupt = TRUE;
 }
 
@@ -45,5 +39,51 @@ NTAPI
 MiniportHandleInterrupt(
     IN NDIS_HANDLE MiniportAdapterContext)
 {
+    ULONG Value;
+    PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
+    volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    Value = InterlockedExchange(&Adapter->InterruptPending, 0);
+
+    NdisDprAcquireSpinLock(&Adapter->Lock);
+
+    if (Value & E1000_IMS_LSC)
+    {
+        ULONG Status;
+        NdisDprReleaseSpinLock(&Adapter->Lock);
+        Value &= ~E1000_IMS_LSC;
+        NDIS_DbgPrint(MIN_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));
+        }
+    }
+
+
+    ASSERT(Value == 0);
 }
index 50b5c44..0df4f76 100644 (file)
@@ -30,9 +30,43 @@ MiniportSend(
     IN PNDIS_PACKET Packet,
     IN UINT Flags)
 {
-    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+    PE1000_ADAPTER Adapter = (PE1000_ADAPTER)MiniportAdapterContext;
+    PSCATTER_GATHER_LIST sgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo);
+    ULONG TransmitLength;
+    ULONG TransmitBuffer;
+    NDIS_STATUS Status;
 
-    return NDIS_STATUS_FAILURE;
+    ASSERT(sgList != NULL);
+    ASSERT(sgList->NumberOfElements == 1);
+    ASSERT(sgList->Elements[0].Address.HighPart == 0);
+    ASSERT((sgList->Elements[0].Address.LowPart & 3) == 0);
+    ASSERT(sgList->Elements[0].Length <= MAXIMUM_FRAME_SIZE);
+
+    NDIS_DbgPrint(MAX_TRACE, ("Sending %d byte packet\n", sgList->Elements[0].Length));
+
+    NdisAcquireSpinLock(&Adapter->Lock);
+
+    if (Adapter->TxFull)
+    {
+        NdisReleaseSpinLock(&Adapter->Lock);
+        NDIS_DbgPrint(MIN_TRACE, ("All TX descriptors are full\n"));
+        return NDIS_STATUS_RESOURCES;
+    }
+
+    TransmitLength = sgList->Elements[0].Length;
+    TransmitBuffer = sgList->Elements[0].Address.LowPart;
+
+    Status = NICTransmitPacket(Adapter, TransmitBuffer, TransmitLength);
+    if (Status != NDIS_STATUS_SUCCESS)
+    {
+        NdisReleaseSpinLock(&Adapter->Lock);
+        NDIS_DbgPrint(MIN_TRACE, ("Transmit packet failed\n"));
+        return Status;
+    }
+
+    NdisReleaseSpinLock(&Adapter->Lock);
+
+    return NDIS_STATUS_SUCCESS;
 }
 
 VOID
index 9586b61..7b42d05 100644 (file)
@@ -21,7 +21,7 @@
 #define DRIVER_VERSION 1
 
 
-#define DEFAULT_INTERRUPT_MASK      (E1000_IMS_LSC)
+#define DEFAULT_INTERRUPT_MASK      (E1000_IMS_LSC | E1000_IMS_TXDW)
 
 typedef struct _E1000_ADAPTER
 {
@@ -63,6 +63,15 @@ typedef struct _E1000_ADAPTER
     ULONG InterruptMask;
     ULONG InterruptPending;
 
+
+    /* Transmit */
+    PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptors;
+    NDIS_PHYSICAL_ADDRESS TransmitDescriptorsPa;
+
+    ULONG CurrentTxDesc;
+    ULONG LastTxDesc;
+    BOOLEAN TxFull;
+
 } E1000_ADAPTER, *PE1000_ADAPTER;
 
 
@@ -143,17 +152,12 @@ NTAPI
 NICDisableInterrupts(
     IN PE1000_ADAPTER Adapter);
 
-USHORT
+ULONG
 NTAPI
 NICInterruptRecognized(
     IN PE1000_ADAPTER Adapter,
     OUT PBOOLEAN InterruptRecognized);
 
-VOID
-NTAPI
-NICAcknowledgeInterrupts(
-    IN PE1000_ADAPTER Adapter);
-
 VOID
 NTAPI
 NICUpdateLinkStatus(
@@ -163,7 +167,6 @@ NDIS_STATUS
 NTAPI
 NICTransmitPacket(
     IN PE1000_ADAPTER Adapter,
-    IN UCHAR TxDesc,
     IN ULONG PhysicalAddress,
     IN ULONG Length);