mirror of
https://github.com/reactos/reactos.git
synced 2025-04-05 21:21:33 +00:00
[E1000] Initial send implementation.
CORE-14675
This commit is contained in:
parent
ebad64bcfe
commit
3606404b2e
4 changed files with 280 additions and 33 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
Loading…
Reference in a new issue