[E1000] Initial send implementation.

CORE-14675
This commit is contained in:
Mark Jansen 2018-06-03 22:43:50 +02:00
parent ebad64bcfe
commit 3606404b2e
4 changed files with 280 additions and 33 deletions

View 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)

View 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);
//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 ring buffer */
E1000WriteUlong(Adapter, E1000_REG_RDBAH, Adapter->ReceiveDescriptorsPa.HighPart);
E1000WriteUlong(Adapter, E1000_REG_RDBAL, Adapter->ReceiveDescriptorsPa.LowPart);
/* 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;

View 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);
}

View 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_ */