https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3606404b2e38974213334a...
commit 3606404b2e38974213334a53da307e89bacf3d03 Author: Mark Jansen mark.jansen@reactos.org AuthorDate: Sun Jun 3 22:43:50 2018 +0200 Commit: Mark Jansen mark.jansen@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_ */