mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[E1000] Implement basic sending.
Implement some interrupt recognition CORE-14675
This commit is contained in:
parent
d9b0601ceb
commit
ebad64bcfe
5 changed files with 269 additions and 32 deletions
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue