https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ebad64bcfe782e1e11845…
commit ebad64bcfe782e1e11845bbed6eb38aa56294236
Author: Mark Jansen <mark.jansen(a)reactos.org>
AuthorDate: Tue May 29 22:52:43 2018 +0200
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Thu Feb 7 19:48:54 2019 +0100
[E1000] Implement basic sending.
Implement some interrupt recognition
CORE-14675
---
drivers/network/dd/e1000/e1000hw.h | 75 +++++++++++++++++++++++-
drivers/network/dd/e1000/hardware.c | 109 +++++++++++++++++++++++++++++++----
drivers/network/dd/e1000/interrupt.c | 60 +++++++++++++++----
drivers/network/dd/e1000/ndis.c | 38 +++++++++++-
drivers/network/dd/e1000/nic.h | 19 +++---
5 files changed, 269 insertions(+), 32 deletions(-)
diff --git a/drivers/network/dd/e1000/e1000hw.h b/drivers/network/dd/e1000/e1000hw.h
index 9932974281..2ee489342a 100644
--- a/drivers/network/dd/e1000/e1000hw.h
+++ b/drivers/network/dd/e1000/e1000hw.h
@@ -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 */
diff --git a/drivers/network/dd/e1000/hardware.c b/drivers/network/dd/e1000/hardware.c
index 5308afadd5..f510d9991d 100644
--- a/drivers/network/dd/e1000/hardware.c
+++ b/drivers/network/dd/e1000/hardware.c
@@ -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;
}
diff --git a/drivers/network/dd/e1000/interrupt.c b/drivers/network/dd/e1000/interrupt.c
index 16e46e76ce..c65196274a 100644
--- a/drivers/network/dd/e1000/interrupt.c
+++ b/drivers/network/dd/e1000/interrupt.c
@@ -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);
}
diff --git a/drivers/network/dd/e1000/ndis.c b/drivers/network/dd/e1000/ndis.c
index 50b5c44e93..0df4f765f0 100644
--- a/drivers/network/dd/e1000/ndis.c
+++ b/drivers/network/dd/e1000/ndis.c
@@ -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
diff --git a/drivers/network/dd/e1000/nic.h b/drivers/network/dd/e1000/nic.h
index 9586b615f6..7b42d055e2 100644
--- a/drivers/network/dd/e1000/nic.h
+++ b/drivers/network/dd/e1000/nic.h
@@ -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);