[E1000] Implement basic sending.

Implement some interrupt recognition

CORE-14675
This commit is contained in:
Mark Jansen 2018-05-29 22:52:43 +02:00
parent d9b0601ceb
commit ebad64bcfe
5 changed files with 269 additions and 32 deletions

View file

@ -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 */

View file

@ -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;
}

View file

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

View file

@ -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

View file

@ -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);