https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3606404b2e38974213334…
commit 3606404b2e38974213334a53da307e89bacf3d03
Author: Mark Jansen <mark.jansen(a)reactos.org>
AuthorDate: Sun Jun 3 22:43:50 2018 +0200
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Thu Feb 7 19:48:54 2019 +0100
[E1000] Initial send implementation.
CORE-14675
---
drivers/network/dd/e1000/e1000hw.h | 35 +++++-
drivers/network/dd/e1000/hardware.c | 203 +++++++++++++++++++++++++++++------
drivers/network/dd/e1000/interrupt.c | 51 +++++++++
drivers/network/dd/e1000/nic.h | 24 ++++-
4 files changed, 280 insertions(+), 33 deletions(-)
diff --git a/drivers/network/dd/e1000/e1000hw.h b/drivers/network/dd/e1000/e1000hw.h
index 2ee489342a..b2293aa0ba 100644
--- a/drivers/network/dd/e1000/e1000hw.h
+++ b/drivers/network/dd/e1000/e1000hw.h
@@ -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)
diff --git a/drivers/network/dd/e1000/hardware.c b/drivers/network/dd/e1000/hardware.c
index f510d9991d..0b7d8f0d1f 100644
--- a/drivers/network/dd/e1000/hardware.c
+++ b/drivers/network/dd/e1000/hardware.c
@@ -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;
diff --git a/drivers/network/dd/e1000/interrupt.c b/drivers/network/dd/e1000/interrupt.c
index c65196274a..cd94e455e1 100644
--- a/drivers/network/dd/e1000/interrupt.c
+++ b/drivers/network/dd/e1000/interrupt.c
@@ -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);
}
diff --git a/drivers/network/dd/e1000/nic.h b/drivers/network/dd/e1000/nic.h
index 7b42d055e2..be198701ed 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 | 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_ */