mirror of
https://github.com/reactos/reactos.git
synced 2024-08-19 18:02:55 +00:00
![Victor Perevertkin](/assets/img/avatar_default.png)
Added PIDs for whole Intel 8254x family. Note: this driver uses legacy interfaces for either receive and transmit descriptors. CORE-14675
855 lines
25 KiB
C
855 lines
25 KiB
C
/*
|
|
* PROJECT: ReactOS Intel PRO/1000 Driver
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Hardware specific functions
|
|
* COPYRIGHT: 2018 Mark Jansen (mark.jansen@reactos.org)
|
|
* 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
|
|
*/
|
|
|
|
#include "nic.h"
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
static USHORT SupportedDevices[] =
|
|
{
|
|
/* 8254x Family adapters. Not all of them are tested */
|
|
0x1000, // Intel 82542
|
|
0x1001, // Intel 82543GC Fiber
|
|
0x1004, // Intel 82543GC Copper
|
|
0x1008, // Intel 82544EI Copper
|
|
0x1009, // Intel 82544EI Fiber
|
|
0x100A, // Intel 82540EM
|
|
0x100C, // Intel 82544GC Copper
|
|
0x100D, // Intel 82544GC LOM (LAN on Motherboard)
|
|
0x100E, // Intel 82540EM
|
|
0x100F, // Intel 82545EM Copper
|
|
0x1010, // Intel 82546EB Copper
|
|
0x1011, // Intel 82545EM Fiber
|
|
0x1012, // Intel 82546EB Fiber
|
|
0x1013, // Intel 82541EI
|
|
0x1014, // Intel 82541EI LOM
|
|
0x1015, // Intel 82540EM LOM
|
|
0x1016, // Intel 82540EP LOM
|
|
0x1017, // Intel 82540EP
|
|
0x1018, // Intel 82541EI Mobile
|
|
0x1019, // Intel 82547EI
|
|
0x101A, // Intel 82547EI Mobile
|
|
0x101D, // Intel 82546EB Quad Copper
|
|
0x101E, // Intel 82540EP LP (Low profile)
|
|
0x1026, // Intel 82545GM Copper
|
|
0x1027, // Intel 82545GM Fiber
|
|
0x1028, // Intel 82545GM SerDes
|
|
0x1075, // Intel 82547GI
|
|
0x1076, // Intel 82541GI
|
|
0x1077, // Intel 82541GI Mobile
|
|
0x1078, // Intel 82541ER
|
|
0x1079, // Intel 82546GB Copper
|
|
0x107A, // Intel 82546GB Fiber
|
|
0x107B, // Intel 82546GB SerDes
|
|
0x107C, // Intel 82541PI
|
|
0x108A, // Intel 82546GB PCI-E
|
|
0x1099, // Intel 82546GB Quad Copper
|
|
0x10B5, // Intel 82546GB Quad Copper KSP3
|
|
};
|
|
|
|
|
|
static ULONG E1000WriteFlush(IN PE1000_ADAPTER Adapter)
|
|
{
|
|
volatile ULONG Value;
|
|
|
|
NdisReadRegisterUlong(Adapter->IoBase + E1000_REG_STATUS, &Value);
|
|
return Value;
|
|
}
|
|
|
|
VOID NTAPI E1000WriteUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value)
|
|
{
|
|
NdisWriteRegisterUlong((PULONG)(Adapter->IoBase + Address), Value);
|
|
}
|
|
|
|
VOID NTAPI E1000ReadUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, OUT PULONG Value)
|
|
{
|
|
NdisReadRegisterUlong((PULONG)(Adapter->IoBase + Address), Value);
|
|
}
|
|
|
|
static VOID E1000WriteIoUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value)
|
|
{
|
|
NdisRawWritePortUlong((PULONG)(Adapter->IoPort), Address);
|
|
E1000WriteFlush(Adapter);
|
|
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;
|
|
}
|
|
|
|
#if 0
|
|
/* This function works, but the driver does not use PHY register access right now */
|
|
static BOOLEAN E1000ReadMdic(IN PE1000_ADAPTER Adapter, IN ULONG Address, USHORT *Result)
|
|
{
|
|
ULONG ResultAddress;
|
|
ULONG Mdic;
|
|
UINT n;
|
|
|
|
if (Address > MAX_PHY_REG_ADDRESS)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("PHY Address %d is invalid\n", Address));
|
|
return 1;
|
|
}
|
|
|
|
Mdic = (Address << E1000_MDIC_REGADD_SHIFT);
|
|
Mdic |= (E1000_MDIC_PHYADD_GIGABIT << E1000_MDIC_PHYADD_SHIFT);
|
|
Mdic |= E1000_MDIC_OP_READ;
|
|
|
|
E1000WriteUlong(Adapter, E1000_REG_MDIC, Mdic);
|
|
|
|
for (n = 0; n < MAX_PHY_READ_ATTEMPTS; n++)
|
|
{
|
|
NdisStallExecution(50);
|
|
E1000ReadUlong(Adapter, E1000_REG_MDIC, &Mdic);
|
|
if (Mdic & E1000_MDIC_R)
|
|
break;
|
|
}
|
|
if (!(Mdic & E1000_MDIC_R))
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("MDI Read incomplete\n"));
|
|
return FALSE;
|
|
}
|
|
if (Mdic & E1000_MDIC_E)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("MDI Read error\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
ResultAddress = (Mdic >> E1000_MDIC_REGADD_SHIFT) & MAX_PHY_REG_ADDRESS;
|
|
|
|
if (ResultAddress!= Address)
|
|
{
|
|
/* Add locking? */
|
|
NDIS_DbgPrint(MIN_TRACE, ("MDI Read got wrong address (%d instead of %d)\n",
|
|
ResultAddress, Address));
|
|
return FALSE;
|
|
}
|
|
*Result = (USHORT) Mdic;
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
static BOOLEAN E1000ReadEeprom(IN PE1000_ADAPTER Adapter, IN UCHAR Address, USHORT *Result)
|
|
{
|
|
ULONG Value;
|
|
UINT n;
|
|
|
|
E1000WriteUlong(Adapter, E1000_REG_EERD, E1000_EERD_START | ((UINT)Address << E1000_EERD_ADDR_SHIFT));
|
|
|
|
for (n = 0; n < MAX_EEPROM_READ_ATTEMPTS; ++n)
|
|
{
|
|
NdisStallExecution(5);
|
|
|
|
E1000ReadUlong(Adapter, E1000_REG_EERD, &Value);
|
|
|
|
if (Value & E1000_EERD_DONE)
|
|
break;
|
|
}
|
|
if (!(Value & E1000_EERD_DONE))
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("EEPROM Read incomplete\n"));
|
|
return FALSE;
|
|
}
|
|
*Result = (USHORT)(Value >> E1000_EERD_DATA_SHIFT);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN E1000ValidateNvmChecksum(IN PE1000_ADAPTER Adapter)
|
|
{
|
|
USHORT Checksum = 0, Data;
|
|
UINT n;
|
|
|
|
/* 5.6.35 Checksum Word Calculation (Word 3Fh) */
|
|
for (n = 0; n <= E1000_NVM_REG_CHECKSUM; n++)
|
|
{
|
|
if (!E1000ReadEeprom(Adapter, n, &Data))
|
|
{
|
|
return FALSE;
|
|
}
|
|
Checksum += Data;
|
|
}
|
|
|
|
if (Checksum != NVM_MAGIC_SUM)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("EEPROM has an invalid checksum of 0x%x\n", (ULONG)Checksum));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
NICRecognizeHardware(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
UINT n;
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
if (Adapter->VendorID != HW_VENDOR_INTEL)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Unknown vendor: 0x%x\n", Adapter->VendorID));
|
|
return FALSE;
|
|
}
|
|
|
|
for (n = 0; n < ARRAYSIZE(SupportedDevices); ++n)
|
|
{
|
|
if (SupportedDevices[n] == Adapter->DeviceID)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
NDIS_DbgPrint(MIN_TRACE, ("Unknown device: 0x%x\n", Adapter->DeviceID));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICInitializeAdapterResources(
|
|
IN PE1000_ADAPTER Adapter,
|
|
IN PNDIS_RESOURCE_LIST ResourceList)
|
|
{
|
|
UINT n;
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
for (n = 0; n < ResourceList->Count; n++)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor = ResourceList->PartialDescriptors + n;
|
|
|
|
switch (ResourceDescriptor->Type)
|
|
{
|
|
case CmResourceTypePort:
|
|
ASSERT(Adapter->IoPortAddress == 0);
|
|
ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0);
|
|
|
|
Adapter->IoPortAddress = ResourceDescriptor->u.Port.Start.LowPart;
|
|
Adapter->IoPortLength = ResourceDescriptor->u.Port.Length;
|
|
|
|
NDIS_DbgPrint(MID_TRACE, ("I/O port range is %p to %p\n",
|
|
Adapter->IoPortAddress,
|
|
Adapter->IoPortAddress + Adapter->IoPortLength));
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
ASSERT(Adapter->InterruptVector == 0);
|
|
ASSERT(Adapter->InterruptLevel == 0);
|
|
|
|
Adapter->InterruptVector = ResourceDescriptor->u.Interrupt.Vector;
|
|
Adapter->InterruptLevel = ResourceDescriptor->u.Interrupt.Level;
|
|
Adapter->InterruptShared = (ResourceDescriptor->ShareDisposition == CmResourceShareShared);
|
|
Adapter->InterruptFlags = ResourceDescriptor->Flags;
|
|
|
|
NDIS_DbgPrint(MID_TRACE, ("IRQ vector is %d\n", Adapter->InterruptVector));
|
|
break;
|
|
case CmResourceTypeMemory:
|
|
/* Internal registers and memories (including PHY) */
|
|
if (ResourceDescriptor->u.Memory.Length == (128 * 1024))
|
|
{
|
|
ASSERT(Adapter->IoAddress.LowPart == 0);
|
|
ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0);
|
|
|
|
|
|
Adapter->IoAddress.QuadPart = ResourceDescriptor->u.Memory.Start.QuadPart;
|
|
Adapter->IoLength = ResourceDescriptor->u.Memory.Length;
|
|
NDIS_DbgPrint(MID_TRACE, ("Memory range is %I64x to %I64x\n",
|
|
Adapter->IoAddress.QuadPart,
|
|
Adapter->IoAddress.QuadPart + Adapter->IoLength));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
NDIS_DbgPrint(MIN_TRACE, ("Unrecognized resource type: 0x%x\n", ResourceDescriptor->Type));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Adapter->IoAddress.QuadPart == 0 || Adapter->IoPortAddress == 0 || Adapter->InterruptVector == 0)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Adapter didn't receive enough resources\n"));
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICAllocateIoResources(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
NDIS_STATUS Status;
|
|
ULONG AllocationSize;
|
|
UINT n;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->IoPort,
|
|
Adapter->AdapterHandle,
|
|
Adapter->IoPortAddress,
|
|
Adapter->IoPortLength);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Unable to register IO port range (0x%x)\n", Status));
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase,
|
|
Adapter->AdapterHandle,
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICRegisterInterrupts(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
NDIS_STATUS Status;
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
|
|
Adapter->AdapterHandle,
|
|
Adapter->InterruptVector,
|
|
Adapter->InterruptLevel,
|
|
TRUE, // We always want ISR calls
|
|
Adapter->InterruptShared,
|
|
(Adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ?
|
|
NdisInterruptLatched : NdisInterruptLevelSensitive);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Adapter->InterruptRegistered = TRUE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICUnregisterInterrupts(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
if (Adapter->InterruptRegistered)
|
|
{
|
|
NdisMDeregisterInterrupt(&Adapter->Interrupt);
|
|
Adapter->InterruptRegistered = FALSE;
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICReleaseIoResources(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
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 */
|
|
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,
|
|
FALSE,
|
|
Adapter->TransmitDescriptors,
|
|
Adapter->TransmitDescriptorsPa);
|
|
|
|
Adapter->TransmitDescriptors = NULL;
|
|
}
|
|
|
|
|
|
|
|
if (Adapter->IoPort)
|
|
{
|
|
NdisMDeregisterIoPortRange(Adapter->AdapterHandle,
|
|
Adapter->IoPortAddress,
|
|
Adapter->IoPortLength,
|
|
Adapter->IoPort);
|
|
}
|
|
|
|
if (Adapter->IoBase)
|
|
{
|
|
NdisMUnmapIoSpace(Adapter->AdapterHandle, Adapter->IoBase, Adapter->IoLength);
|
|
}
|
|
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICPowerOn(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
NDIS_STATUS Status;
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
Status = NICSoftReset(Adapter);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
if (!E1000ValidateNvmChecksum(Adapter))
|
|
{
|
|
return NDIS_STATUS_INVALID_DATA;
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICSoftReset(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
ULONG Value, ResetAttempts;
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
NICDisableInterrupts(Adapter);
|
|
E1000WriteUlong(Adapter, E1000_REG_RCTL, 0);
|
|
E1000WriteUlong(Adapter, E1000_REG_TCTL, 0);
|
|
E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
|
|
/* Write this using IO port, some devices cannot ack this otherwise */
|
|
E1000WriteIoUlong(Adapter, E1000_REG_CTRL, Value | E1000_CTRL_RST);
|
|
|
|
|
|
for (ResetAttempts = 0; ResetAttempts < MAX_RESET_ATTEMPTS; ResetAttempts++)
|
|
{
|
|
/* Wait 1us after reset (according to manual) */
|
|
NdisStallExecution(1);
|
|
E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
|
|
|
|
if (!(Value & E1000_CTRL_RST))
|
|
{
|
|
NDIS_DbgPrint(MAX_TRACE, ("Device is back (%u)\n", ResetAttempts));
|
|
|
|
NICDisableInterrupts(Adapter);
|
|
/* Clear out interrupts (the register is cleared upon read) */
|
|
E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
|
|
|
|
E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
|
|
Value &= ~(E1000_CTRL_LRST|E1000_CTRL_VME);
|
|
Value |= (E1000_CTRL_ASDE|E1000_CTRL_SLU);
|
|
E1000WriteUlong(Adapter, E1000_REG_CTRL, Value);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
NDIS_DbgPrint(MIN_TRACE, ("Device did not recover\n"));
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICEnableTxRx(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
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);
|
|
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;
|
|
|
|
/* Set up interrupt timers */
|
|
E1000WriteUlong(Adapter, E1000_REG_TADV, 96); // value is in 1.024 of usec
|
|
E1000WriteUlong(Adapter, E1000_REG_TIDV, 16);
|
|
|
|
E1000WriteUlong(Adapter, E1000_REG_TCTL, E1000_TCTL_EN | E1000_TCTL_PSP);
|
|
|
|
E1000WriteUlong(Adapter, E1000_REG_TIPG, E1000_TIPG_IPGT_DEF | E1000_TIPG_IPGR1_DEF | E1000_TIPG_IPGR2_DEF);
|
|
|
|
NDIS_DbgPrint(MID_TRACE, ("Setting up receive.\n"));
|
|
|
|
/* Make sure the thing is disabled first. */
|
|
E1000WriteUlong(Adapter, E1000_REG_RCTL, 0);
|
|
|
|
/* 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);
|
|
|
|
/* Set up interrupt timers */
|
|
E1000WriteUlong(Adapter, E1000_REG_RADV, 96);
|
|
E1000WriteUlong(Adapter, E1000_REG_RDTR, 16);
|
|
|
|
/* 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;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
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;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICGetPermanentMacAddress(
|
|
IN PE1000_ADAPTER Adapter,
|
|
OUT PUCHAR MacAddress)
|
|
{
|
|
USHORT AddrWord;
|
|
UINT n;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
/* Should we read from RAL/RAH first? */
|
|
for (n = 0; n < (IEEE_802_ADDR_LENGTH / 2); ++n)
|
|
{
|
|
if (!E1000ReadEeprom(Adapter, (UCHAR)n, &AddrWord))
|
|
return NDIS_STATUS_FAILURE;
|
|
Adapter->PermanentMacAddress[n * 2 + 0] = AddrWord & 0xff;
|
|
Adapter->PermanentMacAddress[n * 2 + 1] = (AddrWord >> 8) & 0xff;
|
|
}
|
|
|
|
NDIS_DbgPrint(MIN_TRACE, ("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
Adapter->PermanentMacAddress[0],
|
|
Adapter->PermanentMacAddress[1],
|
|
Adapter->PermanentMacAddress[2],
|
|
Adapter->PermanentMacAddress[3],
|
|
Adapter->PermanentMacAddress[4],
|
|
Adapter->PermanentMacAddress[5]));
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICUpdateMulticastList(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
UINT n;
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
for (n = 0; n < MAXIMUM_MULTICAST_ADDRESSES; ++n)
|
|
{
|
|
ULONG Ral = *(ULONG *)Adapter->MulticastList[n].MacAddress;
|
|
ULONG Rah = *(USHORT *)&Adapter->MulticastList[n].MacAddress[4];
|
|
|
|
if (Rah || Ral)
|
|
{
|
|
Rah |= E1000_RAH_AV;
|
|
|
|
E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), Ral);
|
|
E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), Rah);
|
|
}
|
|
else
|
|
{
|
|
E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), 0);
|
|
E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), 0);
|
|
}
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICApplyPacketFilter(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
ULONG FilterMask;
|
|
|
|
E1000ReadUlong(Adapter, E1000_REG_RCTL, &FilterMask);
|
|
|
|
FilterMask &= ~E1000_RCTL_FILTER_BITS;
|
|
FilterMask |= PacketFilterToMask(Adapter->PacketFilter);
|
|
E1000WriteUlong(Adapter, E1000_REG_RCTL, FilterMask);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICApplyInterruptMask(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
E1000WriteUlong(Adapter, E1000_REG_IMS, Adapter->InterruptMask /*| 0x1F6DC*/);
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICDisableInterrupts(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
E1000WriteUlong(Adapter, E1000_REG_IMC, ~0);
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
NICInterruptRecognized(
|
|
IN PE1000_ADAPTER Adapter,
|
|
OUT PBOOLEAN InterruptRecognized)
|
|
{
|
|
ULONG Value;
|
|
|
|
/* Reading the interrupt acknowledges them */
|
|
E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
|
|
|
|
*InterruptRecognized = (Value & Adapter->InterruptMask) != 0;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("NICInterruptRecognized(0x%x, 0x%x).\n", Value, *InterruptRecognized));
|
|
|
|
return (Value & Adapter->InterruptMask);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
NICUpdateLinkStatus(
|
|
IN PE1000_ADAPTER Adapter)
|
|
{
|
|
ULONG DeviceStatus;
|
|
SIZE_T SpeedIndex;
|
|
static ULONG SpeedValues[] = { 10, 100, 1000, 1000 };
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus);
|
|
Adapter->MediaState = (DeviceStatus & E1000_STATUS_LU) ? NdisMediaStateConnected : NdisMediaStateDisconnected;
|
|
SpeedIndex = (DeviceStatus & E1000_STATUS_SPEEDMASK) >> E1000_STATUS_SPEEDSHIFT;
|
|
Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex];
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NTAPI
|
|
NICTransmitPacket(
|
|
IN PE1000_ADAPTER Adapter,
|
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
|
IN ULONG Length)
|
|
{
|
|
volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->CurrentTxDesc;
|
|
TransmitDescriptor->Address = PhysicalAddress.QuadPart;
|
|
TransmitDescriptor->Length = Length;
|
|
TransmitDescriptor->ChecksumOffset = 0;
|
|
TransmitDescriptor->Command = E1000_TDESC_CMD_RS | E1000_TDESC_CMD_IFCS | E1000_TDESC_CMD_EOP | E1000_TDESC_CMD_IDE;
|
|
TransmitDescriptor->Status = 0;
|
|
TransmitDescriptor->ChecksumStartField = 0;
|
|
TransmitDescriptor->Special = 0;
|
|
|
|
Adapter->CurrentTxDesc = (Adapter->CurrentTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS;
|
|
|
|
E1000WriteUlong(Adapter, E1000_REG_TDT, Adapter->CurrentTxDesc);
|
|
|
|
if (Adapter->CurrentTxDesc == Adapter->LastTxDesc)
|
|
{
|
|
NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n"));
|
|
Adapter->TxFull = TRUE;
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|