From ebad64bcfe782e1e11845bbed6eb38aa56294236 Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Tue, 29 May 2018 22:52:43 +0200 Subject: [PATCH] [E1000] Implement basic sending. Implement some interrupt recognition CORE-14675 --- drivers/network/dd/e1000/e1000hw.h | 75 +++++++++++++++++- drivers/network/dd/e1000/hardware.c | 109 ++++++++++++++++++++++++--- drivers/network/dd/e1000/interrupt.c | 60 ++++++++++++--- drivers/network/dd/e1000/ndis.c | 38 +++++++++- drivers/network/dd/e1000/nic.h | 19 +++-- 5 files changed, 269 insertions(+), 32 deletions(-) diff --git a/drivers/network/dd/e1000/e1000hw.h b/drivers/network/dd/e1000/e1000hw.h index 99329742812..2ee489342a4 100644 --- a/drivers/network/dd/e1000/e1000hw.h +++ b/drivers/network/dd/e1000/e1000hw.h @@ -32,6 +32,61 @@ typedef struct _ETH_HEADER { +#include + + +/* 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 + + +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 */ diff --git a/drivers/network/dd/e1000/hardware.c b/drivers/network/dd/e1000/hardware.c index 5308afadd55..f510d9991d4 100644 --- a/drivers/network/dd/e1000/hardware.c +++ b/drivers/network/dd/e1000/hardware.c @@ -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; } diff --git a/drivers/network/dd/e1000/interrupt.c b/drivers/network/dd/e1000/interrupt.c index 16e46e76ce2..c65196274a7 100644 --- a/drivers/network/dd/e1000/interrupt.c +++ b/drivers/network/dd/e1000/interrupt.c @@ -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); } diff --git a/drivers/network/dd/e1000/ndis.c b/drivers/network/dd/e1000/ndis.c index 50b5c44e93c..0df4f765f0d 100644 --- a/drivers/network/dd/e1000/ndis.c +++ b/drivers/network/dd/e1000/ndis.c @@ -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 diff --git a/drivers/network/dd/e1000/nic.h b/drivers/network/dd/e1000/nic.h index 9586b615f64..7b42d055e26 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) +#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);