https://git.reactos.org/?p=reactos.git;a=commitdiff;h=59d8a77df6a7245654bdd4...
commit 59d8a77df6a7245654bdd4f31ebc5825282411bf Author: Dmitry Borisov di.sean@protonmail.com AuthorDate: Wed Oct 18 23:12:36 2023 +0600 Commit: GitHub noreply@github.com CommitDate: Wed Oct 18 20:12:36 2023 +0300
[DC21X4] Add driver for DECchip 21x4-compatible network adapters (#5614)
These adapters were common in DEC Alpha boxes and they are really rare nowadays. The 21140 chip is emulated in Connectix / Microsoft Virtual PC and Hyper-V Gen 1 VM.
This is an experimental driver, not yet tested on real hardware.
CORE-8724 --- boot/bootdata/packages/reactos.dff.in | 2 - drivers/network/dd/CMakeLists.txt | 1 + drivers/network/dd/dc21x4/CMakeLists.txt | 40 + drivers/network/dd/dc21x4/dc21x4.c | 401 ++++++++ drivers/network/dd/dc21x4/dc21x4.h | 541 +++++++++++ drivers/network/dd/dc21x4/dc21x4.rc | 5 + drivers/network/dd/dc21x4/dc21x4hw.h | 597 ++++++++++++ drivers/network/dd/dc21x4/debug.c | 70 ++ drivers/network/dd/dc21x4/debug.h | 96 ++ drivers/network/dd/dc21x4/eeprom.c | 1525 ++++++++++++++++++++++++++++++ drivers/network/dd/dc21x4/eeprom.h | 108 +++ drivers/network/dd/dc21x4/eeprom_data.c | 219 +++++ drivers/network/dd/dc21x4/hardware.c | 585 ++++++++++++ drivers/network/dd/dc21x4/init.c | 1321 ++++++++++++++++++++++++++ drivers/network/dd/dc21x4/interrupt.c | 625 ++++++++++++ drivers/network/dd/dc21x4/media.c | 634 +++++++++++++ drivers/network/dd/dc21x4/media.h | 127 +++ drivers/network/dd/dc21x4/media040.c | 143 +++ drivers/network/dd/dc21x4/media041.c | 222 +++++ drivers/network/dd/dc21x4/media140.c | 136 +++ drivers/network/dd/dc21x4/media143.c | 510 ++++++++++ drivers/network/dd/dc21x4/net21x4.inf | 158 ++++ drivers/network/dd/dc21x4/phy.c | 263 ++++++ drivers/network/dd/dc21x4/power.c | 252 +++++ drivers/network/dd/dc21x4/requests.c | 660 +++++++++++++ drivers/network/dd/dc21x4/send.c | 313 ++++++ drivers/network/dd/dc21x4/sendrcv.h | 115 +++ drivers/network/dd/dc21x4/util.h | 84 ++ 28 files changed, 9751 insertions(+), 2 deletions(-)
diff --git a/boot/bootdata/packages/reactos.dff.in b/boot/bootdata/packages/reactos.dff.in index dbf0737ff83..04ad4dc83a0 100644 --- a/boot/bootdata/packages/reactos.dff.in +++ b/boot/bootdata/packages/reactos.dff.in @@ -138,8 +138,6 @@ Signature = "$Windows NT$" "modules/optional/bcmwl5.sys" 3 optional "modules/optional/alcxwdm.inf" 6 optional "modules/optional/alcxwdm.sys" 3 optional -"modules/optional/net21x4.inf" 6 optional -"modules/optional/dc21x4.sys" 3 optional "modules/optional/mfc42.dll" 2 optional "modules/optional/mfc42u.dll" 2 optional "modules/optional/mfc71.dll" 2 optional diff --git a/drivers/network/dd/CMakeLists.txt b/drivers/network/dd/CMakeLists.txt index f8b967412a3..122b82823f7 100644 --- a/drivers/network/dd/CMakeLists.txt +++ b/drivers/network/dd/CMakeLists.txt @@ -1,4 +1,5 @@
+add_subdirectory(dc21x4) add_subdirectory(e1000) add_subdirectory(ne2000) add_subdirectory(netkvm) diff --git a/drivers/network/dd/dc21x4/CMakeLists.txt b/drivers/network/dd/dc21x4/CMakeLists.txt new file mode 100644 index 00000000000..74f6927076f --- /dev/null +++ b/drivers/network/dd/dc21x4/CMakeLists.txt @@ -0,0 +1,40 @@ + +add_definitions( + -DNDIS_MINIPORT_DRIVER + -DNDIS51_MINIPORT=1) + +list(APPEND SOURCE + dc21x4.c + dc21x4.h + dc21x4hw.h + debug.h + eeprom.c + eeprom.h + eeprom_data.c + hardware.c + init.c + interrupt.c + media.c + media040.c + media041.c + media140.c + media143.c + phy.c + power.c + requests.c + send.c + util.h) + +if(DBG) + list(APPEND SOURCE debug.c) +endif() + +add_library(dc21x4 MODULE ${SOURCE} dc21x4.rc) +if(DBG) + target_link_libraries(dc21x4 memcmp) +endif() +add_pch(dc21x4 dc21x4.h SOURCE) +set_module_type(dc21x4 kernelmodedriver) +add_importlibs(dc21x4 ndis ntoskrnl hal) +add_cd_file(TARGET dc21x4 DESTINATION reactos/system32/drivers FOR all) +add_driver_inf(dc21x4 net21x4.inf) diff --git a/drivers/network/dd/dc21x4/dc21x4.c b/drivers/network/dd/dc21x4/dc21x4.c new file mode 100644 index 00000000000..f061c7f5fd5 --- /dev/null +++ b/drivers/network/dd/dc21x4/dc21x4.c @@ -0,0 +1,401 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Miniport driver entry + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +/* INCLUDES *******************************************************************/ + +#include "dc21x4.h" + +#include <debug.h> + +/* FUNCTIONS ******************************************************************/ + +ULONG +DcEthernetCrc( + _In_reads_bytes_(Size) const VOID* Buffer, + _In_ ULONG Size) +{ + ULONG i, j, Crc; + const UCHAR* Data = Buffer; + + Crc = 0xFFFFFFFF; + for (i = 0; i < Size; ++i) + { + Crc ^= Data[i]; + for (j = 8; j > 0; j--) + { + /* CRC-32 polynomial little-endian */ + Crc = (Crc >> 1) ^ (-(LONG)(Crc & 1) & 0xEDB88320); + } + } + + return Crc; +} + +static +VOID +DcFlushTransmitQueue( + _In_ PDC21X4_ADAPTER Adapter) +{ + LIST_ENTRY DoneList; + PLIST_ENTRY Entry; + PNDIS_PACKET Packet; + PDC_TCB Tcb; + + InitializeListHead(&DoneList); + + NdisAcquireSpinLock(&Adapter->SendLock); + + /* Remove pending transmissions from the transmit ring */ + for (Tcb = Adapter->LastTcb; + Tcb != Adapter->CurrentTcb; + Tcb = DC_NEXT_TCB(Adapter, Tcb)) + { + Packet = Tcb->Packet; + + if (!Packet) + continue; + + InsertTailList(&DoneList, DC_LIST_ENTRY_FROM_PACKET(Packet)); + + DC_RELEASE_TCB(Adapter, Tcb); + } + Adapter->CurrentTcb = Tcb; + + /* Remove pending transmissions from the internal queue */ + while (!IsListEmpty(&Adapter->SendQueueList)) + { + Entry = RemoveHeadList(&Adapter->SendQueueList); + + InsertTailList(&DoneList, Entry); + } + + NdisReleaseSpinLock(&Adapter->SendLock); + + while (!IsListEmpty(&DoneList)) + { + Entry = RemoveHeadList(&DoneList); + + NdisMSendComplete(Adapter->AdapterHandle, + DC_PACKET_FROM_LIST_ENTRY(Entry), + NDIS_STATUS_FAILURE); + } +} + +static +VOID +DcStopReceivePath( + _In_ PDC21X4_ADAPTER Adapter) +{ + BOOLEAN RxStopped; + + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + +#if DBG + NdisAcquireSpinLock(&Adapter->ReceiveLock); + if (Adapter->RcbFree != Adapter->RcbCount) + { + INFO("RX packets: %u/%u\n", Adapter->RcbFree, Adapter->RcbCount); + } + NdisReleaseSpinLock(&Adapter->ReceiveLock); +#endif + + while (TRUE) + { + NdisAcquireSpinLock(&Adapter->ReceiveLock); + + RxStopped = (Adapter->RcbFree == Adapter->RcbCount); + + NdisReleaseSpinLock(&Adapter->ReceiveLock); + + if (RxStopped) + break; + + NdisMSleep(10); + } +} + +DECLSPEC_NOINLINE /* Called from pageable code */ +VOID +DcStopAdapter( + _In_ PDC21X4_ADAPTER Adapter, + _In_ BOOLEAN WaitForPackets) +{ + BOOLEAN TimerCancelled; + + /* Attempt to disable interrupts to complete more quickly */ + DC_WRITE(Adapter, DcCsr7_IrqMask, 0); + + /* Prevent DPCs from executing and stop accepting incoming packets */ + NdisAcquireSpinLock(&Adapter->SendLock); + Adapter->Flags &= ~DC_ACTIVE; + NdisReleaseSpinLock(&Adapter->SendLock); + + NdisMCancelTimer(&Adapter->MediaMonitorTimer, &TimerCancelled); + + /* Wait for any DPCs to complete */ + KeFlushQueuedDpcs(); + + /* Disable interrupts */ + DC_WRITE(Adapter, DcCsr7_IrqMask, 0); + + /* Wait for completion of TX/RX and stop the DMA engine inside the NIC */ + DcStopTxRxProcess(Adapter); + Adapter->OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE); + + DcFlushTransmitQueue(Adapter); + + /* Wait for the packets to be returned to the driver */ + if (WaitForPackets) + { + DcStopReceivePath(Adapter); + } + + /* Make sure there is no pending OID request */ + if (Adapter->OidPending) + { + NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS); + + Adapter->OidPending = FALSE; + } +} + +CODE_SEG("PAGE") +VOID +DcStartAdapter( + _In_ PDC21X4_ADAPTER Adapter) +{ + PAGED_CODE(); + + /* Enable interrupts */ + _InterlockedExchange((PLONG)&Adapter->CurrentInterruptMask, Adapter->InterruptMask); + DC_WRITE(Adapter, DcCsr7_IrqMask, Adapter->InterruptMask); + + Adapter->Flags |= DC_ACTIVE; + + /* Start the RX process */ + Adapter->OpMode |= DC_OPMODE_RX_ENABLE; + DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode); + + /* Start the media monitor, wait the selected media to become ready */ + NdisMSetTimer(&Adapter->MediaMonitorTimer, 2400); +} + +CODE_SEG("PAGE") +VOID +NTAPI +DcResetWorker( + _In_ PNDIS_WORK_ITEM WorkItem, + _In_opt_ PVOID Context) +{ + PDC21X4_ADAPTER Adapter = Context; + NDIS_STATUS Status; + ULONG InterruptStatus; + LONG ResetReason; + + UNREFERENCED_PARAMETER(WorkItem); + + PAGED_CODE(); + + Status = NDIS_STATUS_SUCCESS; + + /* Check if the device is present */ + InterruptStatus = DC_READ(Adapter, DcCsr5_Status); + if (InterruptStatus == 0xFFFFFFFF) + { + ERR("Hardware is gone...\n"); + + /* Remove this adapter */ + NdisMRemoveMiniport(Adapter->AdapterHandle); + + Status = NDIS_STATUS_HARD_ERRORS; + goto Done; + } + + DcStopAdapter(Adapter, FALSE); + + if (Adapter->LinkUp) + { + Adapter->LinkUp = FALSE; + + NdisMIndicateStatus(Adapter->AdapterHandle, + NDIS_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + NdisMIndicateStatusComplete(Adapter->AdapterHandle); + } + + DcSetupAdapter(Adapter); + + DcStartAdapter(Adapter); + +Done: + ResetReason = _InterlockedExchange(&Adapter->ResetLock, 0); + + /* Complete the pending reset request */ + if (ResetReason == 1) + { + NdisMResetComplete(Adapter->AdapterHandle, Status, FALSE); + } +} + +VOID +NTAPI +DcTransmitTimeoutRecoveryWorker( + _In_ PNDIS_WORK_ITEM WorkItem, + _In_opt_ PVOID Context) +{ + PDC21X4_ADAPTER Adapter = Context; + + UNREFERENCED_PARAMETER(WorkItem); + + NdisAcquireSpinLock(&Adapter->ModeLock); + + DcStopTxRxProcess(Adapter); + DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode); + + NdisDprAcquireSpinLock(&Adapter->SendLock); + + DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL); + + NdisDprReleaseSpinLock(&Adapter->SendLock); + + NdisReleaseSpinLock(&Adapter->ModeLock); +} + +static +BOOLEAN +NTAPI +DcCheckForHang( + _In_ NDIS_HANDLE MiniportAdapterContext) +{ + PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; + ULONG TcbCompleted; + BOOLEAN TxHang = FALSE; + + if (!(Adapter->Flags & DC_ACTIVE)) + return FALSE; + + NdisDprAcquireSpinLock(&Adapter->SendLock); + + if (Adapter->TcbSlots != (DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE)) + { + TcbCompleted = Adapter->TcbCompleted; + TxHang = (TcbCompleted == Adapter->LastTcbCompleted); + Adapter->LastTcbCompleted = TcbCompleted; + } + + NdisDprReleaseSpinLock(&Adapter->SendLock); + + if (TxHang) + { + WARN("Transmit timeout, CSR12 %08lx, CSR5 %08lx\n", + DC_READ(Adapter, DcCsr12_SiaStatus), + DC_READ(Adapter, DcCsr5_Status)); + + NdisScheduleWorkItem(&Adapter->TxRecoveryWorkItem); + } + + return FALSE; +} + +static +NDIS_STATUS +NTAPI +DcReset( + _Out_ PBOOLEAN AddressingReset, + _In_ NDIS_HANDLE MiniportAdapterContext) +{ + PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; + + WARN("Called\n"); + + if (_InterlockedCompareExchange(&Adapter->ResetLock, 1, 0)) + { + return NDIS_STATUS_RESET_IN_PROGRESS; + } + + NdisScheduleWorkItem(&Adapter->ResetWorkItem); + + return NDIS_STATUS_PENDING; +} + +static +CODE_SEG("PAGE") +VOID +NTAPI +DcHalt( + _In_ NDIS_HANDLE MiniportAdapterContext) +{ + PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; + + PAGED_CODE(); + + INFO("Called\n"); + + DcStopAdapter(Adapter, TRUE); + + DcDisableHw(Adapter); + + DcFreeAdapter(Adapter); +} + +static +VOID +NTAPI +DcShutdown( + _In_ NDIS_HANDLE MiniportAdapterContext) +{ + PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; + + INFO("Called\n"); + + DcDisableHw(Adapter); +} + +CODE_SEG("INIT") +NTSTATUS +NTAPI +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath) +{ + NDIS_HANDLE WrapperHandle; + NDIS_STATUS Status; + NDIS_MINIPORT_CHARACTERISTICS Characteristics = { 0 }; + + INFO("Called\n"); + + NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL); + if (!WrapperHandle) + return NDIS_STATUS_FAILURE; + + Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION; + Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION; + Characteristics.CheckForHangHandler = DcCheckForHang; + Characteristics.HaltHandler = DcHalt; + Characteristics.HandleInterruptHandler = DcHandleInterrupt; + Characteristics.InitializeHandler = DcInitialize; + Characteristics.ISRHandler = DcIsr; + Characteristics.QueryInformationHandler = DcQueryInformation; + Characteristics.ResetHandler = DcReset; + Characteristics.SetInformationHandler = DcSetInformation; + Characteristics.ReturnPacketHandler = DcReturnPacket; + Characteristics.SendPacketsHandler = DcSendPackets; + Characteristics.CancelSendPacketsHandler = DcCancelSendPackets; + Characteristics.AdapterShutdownHandler = DcShutdown; + + Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics)); + if (Status != NDIS_STATUS_SUCCESS) + { + NdisTerminateWrapper(WrapperHandle, NULL); + return Status; + } + + InitializeListHead(&SRompAdapterList); + + return NDIS_STATUS_SUCCESS; +} diff --git a/drivers/network/dd/dc21x4/dc21x4.h b/drivers/network/dd/dc21x4/dc21x4.h new file mode 100644 index 00000000000..20d62fc15ae --- /dev/null +++ b/drivers/network/dd/dc21x4/dc21x4.h @@ -0,0 +1,541 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Main header file + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +#pragma once + +#if !DBG +#define NO_KERNEL_LIST_ENTRY_CHECKS +#endif +#include <ndis.h> +#include <section_attribs.h> + +#include "dc21x4hw.h" +#include "eeprom.h" +#include "media.h" +#include "util.h" + +#define DC21X4_TAG '4x12' + +#define DC_TRANSMIT_DESCRIPTORS 64 +#define DC_TRANSMIT_BLOCKS 48 +#define DC_TRANSMIT_BUFFERS 4 +#define DC_LOOPBACK_FRAMES 4 + +#define DC_RECEIVE_BUFFERS_DEFAULT 64 +#define DC_RECEIVE_BUFFERS_MIN 8 +#define DC_RECEIVE_BUFFERS_EXTRA 16 + +#define DC_RECEIVE_ARRAY_SIZE 16 + +#define DC_MULTICAST_LIST_SIZE 36 + +#define DC_MAXIMUM_FRAME_SIZE 1514 +#define DC_TRANSMIT_BLOCK_SIZE 1536 +#define DC_RECEIVE_BLOCK_SIZE 1536 +#define DC_ETHERNET_HEADER_SIZE 14 + +#define DC_TX_UNDERRUN_LIMIT 5 +#define DC_INTERRUPT_PROCESSING_LIMIT 8 + +#define DC_FRAGMENTATION_THRESHOLD 32 + +#define DC_PACKET_FILTERS ( \ + NDIS_PACKET_TYPE_DIRECTED | \ + NDIS_PACKET_TYPE_MULTICAST | \ + NDIS_PACKET_TYPE_BROADCAST | \ + NDIS_PACKET_TYPE_PROMISCUOUS | \ + NDIS_PACKET_TYPE_ALL_MULTICAST) + +#define DC_LOOPBACK_FRAME_SIZE 64 + +/* Transmit descriptors reserved for internal use */ +#define DC_TBD_RESERVE (2 + DC_LOOPBACK_FRAMES) /* (+2 for setup frame) */ +#define DC_TCB_RESERVE (1 + DC_LOOPBACK_FRAMES) /* (+1 for setup frame) */ + +#define DC_EVENT_SETUP_FRAME_COMPLETED 0x00000001 + +typedef struct _DC21X4_ADAPTER DC21X4_ADAPTER, *PDC21X4_ADAPTER; +typedef struct _DC_TCB DC_TCB, *PDC_TCB; +typedef struct _DC_RCB DC_RCB, *PDC_RCB; +typedef struct _DC_COALESCE_BUFFER DC_COALESCE_BUFFER, *PDC_COALESCE_BUFFER; + +typedef VOID +(MEDIA_HANDLE_LINK_STATE_CHANGE)( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG InterruptStatus); +typedef MEDIA_HANDLE_LINK_STATE_CHANGE *PMEDIA_HANDLE_LINK_STATE_CHANGE; + +typedef struct _DC_TX_BUFFER_DATA +{ + PVOID VirtualAddress; + NDIS_PHYSICAL_ADDRESS PhysicalAddress; +} DC_TX_BUFFER_DATA, *PDC_TX_BUFFER_DATA; + +typedef struct _DC_STATISTICS +{ + ULONG64 TransmitOk; + ULONG64 TransmitDeferred; + ULONG64 TransmitHeartbeatErrors; + ULONG64 TransmitOneRetry; + ULONG64 TransmitMoreCollisions; + ULONG64 TransmitErrors; + ULONG64 TransmitExcessiveCollisions; + ULONG64 TransmitUnderrunErrors; + ULONG64 TransmitLostCarrierSense; + ULONG64 TransmitLateCollisions; + ULONG64 ReceiveOk; + ULONG64 ReceiveBroadcast; + ULONG64 ReceiveMulticast; + ULONG64 ReceiveUnicast; + ULONG64 ReceiveErrors; + ULONG64 ReceiveOverrunErrors; + ULONG64 ReceiveNoBuffers; + ULONG64 ReceiveCrcErrors; + ULONG64 ReceiveAlignmentErrors; +} DC_STATISTICS, *PDC_STATISTICS; + +typedef struct _DC21X4_ADAPTER +{ + PUCHAR IoBase; + ULONG InterruptMask; + ULONG CurrentInterruptMask; + + ULONG Features; +#define DC_NEED_RX_OVERFLOW_WORKAROUND 0x80000000 +#define DC_SIA_GPIO 0x00000001 +#define DC_SIA_ANALOG_CONTROL 0x00000002 +#define DC_HAS_POWER_MANAGEMENT 0x00000004 +#define DC_HAS_POWER_SAVING 0x00000008 +#define DC_HAS_MII 0x00000010 +#define DC_PERFECT_FILTERING_ONLY 0x00000020 +#define DC_ENABLE_PCI_COMMANDS 0x00000040 +#define DC_MII_AUTOSENSE 0x00000080 +#define DC_HAS_TIMER 0x00000100 + + ULONG Flags; +#define DC_ACTIVE 0x80000000 +#define DC_IO_MAPPED 0x00000001 +#define DC_IRQ_SHARED 0x00000002 +#define DC_FIRST_SETUP 0x00000004 +#define DC_AUTOSENSE 0x00000008 + + ULONG InterruptStatus; + PMEDIA_HANDLE_LINK_STATE_CHANGE HandleLinkStateChange; + + DECLSPEC_CACHEALIGN NDIS_SPIN_LOCK SendLock; + PDC_TCB TailTcb; + PDC_TCB LastTcb; + PDC_TCB CurrentTcb; + PDC_TBD CurrentTbd; + PDC_TBD HeadTbd; + PDC_TBD TailTbd; + LIST_ENTRY SendQueueList; + ULONG TcbSlots; + ULONG TbdSlots; + ULONG TcbCompleted; + ULONG LastTcbCompleted; + PDC_TCB HeadTcb; + SINGLE_LIST_ENTRY SendBufferList; + SCATTER_GATHER_LIST LocalSgList; + + DECLSPEC_CACHEALIGN NDIS_SPIN_LOCK ReceiveLock; + PDC_RCB* RcbArray; + PDC_RBD CurrentRbd; + PDC_RBD HeadRbd; + PDC_RBD TailRbd; + SINGLE_LIST_ENTRY FreeRcbList; + ULONG RcbFree; + + ULONG TransmitUnderruns; + ULONG PacketFilter; + + DC_STATISTICS Statistics; + + NDIS_HANDLE AdapterHandle; + NDIS_HANDLE WrapperConfigurationHandle; + + DECLSPEC_CACHEALIGN NDIS_SPIN_LOCK ModeLock; + ULONG ModeFlags; +#define DC_MODE_AUTONEG_MASK 0x0000000F +#define DC_MODE_PORT_AUTOSENSE 0x00000010 +#define DC_MODE_TEST_PACKET 0x00000020 +#define DC_MODE_AUI_FAILED 0x00000040 +#define DC_MODE_BNC_FAILED 0x00000080 + +#define DC_MODE_AUTONEG_NONE 0x00000000 +#define DC_MODE_AUTONEG_WAIT_INTERRUPT 0x00000001 +#define DC_MODE_AUTONEG_LINK_STATUS_CHECK 0x00000002 + + ULONG OpMode; + ULONG MediaNumber; + ULONG MediaBitmap; + BOOLEAN LinkUp; + ULONG PhyAddress; + ULONG SiaSetting; + ULONG LastReceiveActivity; + volatile LONG MediaTestStatus; + NDIS_MINIPORT_TIMER MediaMonitorTimer; + DC_MII_MEDIA MiiMedia; + DC_MEDIA Media[MEDIA_LIST_MAX]; + + ULONG AnalogControl; + ULONG SymAdvertising; + ULONG MiiAdvertising; + ULONG MiiControl; + DC_CHIP_TYPE ChipType; + ULONG LinkStateChangeMask; + + ULONG WakeUpFlags; + NDIS_DEVICE_POWER_STATE PowerState; + NDIS_DEVICE_POWER_STATE PrevPowerState; + + ULONG HpnaInitBitmap; + UCHAR HpnaRegister[32]; + + UCHAR PermanentMacAddress[ETH_LENGTH_OF_ADDRESS]; + UCHAR CurrentMacAddress[ETH_LENGTH_OF_ADDRESS]; + + ULONG MulticastMaxEntries; + _Field_range_(0, MulticastMaxEntries) + ULONG MulticastCount; + struct + { + UCHAR MacAddress[ETH_LENGTH_OF_ADDRESS]; + } MulticastList[DC_MULTICAST_LIST_SIZE]; + + ULONG LinkSpeedMbps; + ULONG BusMode; + ULONG DefaultMedia; + ULONG RcbCount; + BOOLEAN OidPending; + BOOLEAN ProgramHashPerfectFilter; + PULONG SetupFrame; + PULONG SetupFrameSaved; + ULONG SetupFramePhys; + ULONG LoopbackFrameSlots; + ULONG LoopbackFrameNumber; + ULONG LoopbackFramePhys[DC_LOOPBACK_FRAMES]; + ULONG BusNumber; + UCHAR DeviceNumber; + UCHAR RevisionId; + UCHAR ControllerIndex; + UCHAR ResetStreamLength; + USHORT ResetStream[SROM_MAX_STREAM_REGS]; + USHORT DeviceId; + SINGLE_LIST_ENTRY AllocRcbList; + SINGLE_LIST_ENTRY UsedRcbList; + NDIS_MINIPORT_INTERRUPT Interrupt; + ULONG InterruptVector; + ULONG InterruptLevel; + ULONG InterruptFlags; + ULONG AdapterSize; + NDIS_WORK_ITEM PowerWorkItem; + NDIS_WORK_ITEM ResetWorkItem; + NDIS_WORK_ITEM TxRecoveryWorkItem; + _Interlocked_ volatile LONG ResetLock; + NDIS_PHYSICAL_ADDRESS IoBaseAddress; + PDC_SROM_ENTRY SRomEntry; + PVOID AdapterOriginal; + PVOID TbdOriginal; + PVOID RbdOriginal; + ULONG TbdPhys; + ULONG RbdPhys; + NDIS_HANDLE BufferPool; + NDIS_HANDLE PacketPool; + NDIS_PHYSICAL_ADDRESS TbdPhysOriginal; + NDIS_PHYSICAL_ADDRESS RbdPhysOriginal; + PVOID LoopbackFrame[DC_LOOPBACK_FRAMES]; + PDC_COALESCE_BUFFER CoalesceBuffer; + DC_TX_BUFFER_DATA SendBufferData[DC_TRANSMIT_BUFFERS]; +} DC21X4_ADAPTER, *PDC21X4_ADAPTER; + +#include "sendrcv.h" + +extern LIST_ENTRY SRompAdapterList; + +FORCEINLINE +ULONG +DC_READ( + _In_ PDC21X4_ADAPTER Adapter, + _In_ DC_CSR Register) +{ + ULONG Value; + + NdisRawReadPortUlong((PULONG)(Adapter->IoBase + Register), &Value); + return Value; +} + +#define DC_WRITE(Adapter, Register, Value) \ + NdisRawWritePortUlong((PULONG)((Adapter)->IoBase + (Register)), (Value)); + +CODE_SEG("INIT") +DRIVER_INITIALIZE DriverEntry; + +CODE_SEG("PAGE") +NDIS_STATUS +NTAPI +DcInitialize( + _Out_ PNDIS_STATUS OpenErrorStatus, + _Out_ PUINT SelectedMediumIndex, + _In_ PNDIS_MEDIUM MediumArray, + _In_ UINT MediumArraySize, + _In_ NDIS_HANDLE MiniportAdapterHandle, + _In_ NDIS_HANDLE WrapperConfigurationContext); + +VOID +NTAPI +DcSendPackets( + _In_ NDIS_HANDLE MiniportAdapterContext, + _In_ PPNDIS_PACKET PacketArray, + _In_ UINT NumberOfPackets); + +VOID +NTAPI +DcCancelSendPackets( + _In_ NDIS_HANDLE MiniportAdapterContext, + _In_ PVOID CancelId); + +VOID +DcProcessPendingPackets( + _In_ PDC21X4_ADAPTER Adapter); + +VOID +NTAPI +DcReturnPacket( + _In_ NDIS_HANDLE MiniportAdapterContext, + _In_ PNDIS_PACKET Packet); + +NDIS_STATUS +NTAPI +DcQueryInformation( + _In_ NDIS_HANDLE MiniportAdapterContext, + _In_ NDIS_OID Oid, + _In_ PVOID InformationBuffer, + _In_ ULONG InformationBufferLength, + _Out_ PULONG BytesWritten, + _Out_ PULONG BytesNeeded); + +NDIS_STATUS +NTAPI +DcSetInformation( + _In_ NDIS_HANDLE MiniportAdapterContext, + _In_ NDIS_OID Oid, + _In_ PVOID InformationBuffer, + _In_ ULONG InformationBufferLength, + _Out_ PULONG BytesRead, + _Out_ PULONG BytesNeeded); + +VOID +NTAPI +DcIsr( + _Out_ PBOOLEAN InterruptRecognized, + _Out_ PBOOLEAN QueueMiniportHandleInterrupt, + _In_ NDIS_HANDLE MiniportAdapterContext); + +VOID +NTAPI +DcHandleInterrupt( + _In_ NDIS_HANDLE MiniportAdapterContext); + +CODE_SEG("PAGE") +VOID +NTAPI +DcPowerWorker( + _In_ PNDIS_WORK_ITEM WorkItem, + _In_opt_ PVOID Context); + +NDIS_STATUS +DcSetPower( + _In_ PDC21X4_ADAPTER Adapter, + _In_ NDIS_DEVICE_POWER_STATE PowerState); + +NDIS_STATUS +DcAddWakeUpPattern( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PNDIS_PM_PACKET_PATTERN PmPattern); + +NDIS_STATUS +DcRemoveWakeUpPattern( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PNDIS_PM_PACKET_PATTERN PmPattern); + +CODE_SEG("PAGE") +VOID +DcFreeAdapter( + _In_ __drv_freesMem(Mem) PDC21X4_ADAPTER Adapter); + +CODE_SEG("PAGE") +VOID +NTAPI +DcResetWorker( + _In_ PNDIS_WORK_ITEM WorkItem, + _In_opt_ PVOID Context); + +DECLSPEC_NOINLINE +VOID +DcStopAdapter( + _In_ PDC21X4_ADAPTER Adapter, + _In_ BOOLEAN WaitForPackets); + +CODE_SEG("PAGE") +VOID +DcStartAdapter( + _In_ PDC21X4_ADAPTER Adapter); + +CODE_SEG("PAGE") +NDIS_STATUS +DcSetupAdapter( + _In_ PDC21X4_ADAPTER Adapter); + +CODE_SEG("PAGE") +NDIS_STATUS +DcReadEeprom( + _In_ PDC21X4_ADAPTER Adapter); + +CODE_SEG("PAGE") +VOID +DcFreeEeprom( + _In_ PDC21X4_ADAPTER Adapter); + +CODE_SEG("PAGE") +VOID +DcInitTxRing( + _In_ PDC21X4_ADAPTER Adapter); + +CODE_SEG("PAGE") +VOID +DcInitRxRing( + _In_ PDC21X4_ADAPTER Adapter); + +ULONG +DcEthernetCrc( + _In_reads_bytes_(Size) const VOID* Buffer, + _In_ ULONG Size); + +VOID +DcDisableHw( + _In_ PDC21X4_ADAPTER Adapter); + +VOID +DcStopTxRxProcess( + _In_ PDC21X4_ADAPTER Adapter); + +VOID +DcWriteGpio( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG Value); + +VOID +DcWriteSia( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG Csr13, + _In_ ULONG Csr14, + _In_ ULONG Csr15); + +VOID +DcTestPacket( + _In_ PDC21X4_ADAPTER Adapter); + +CODE_SEG("PAGE") +VOID +DcSetupFrameInitialize( + _In_ PDC21X4_ADAPTER Adapter); + +BOOLEAN +DcSetupFrameDownload( + _In_ PDC21X4_ADAPTER Adapter, + _In_ BOOLEAN WaitForCompletion); + +NDIS_STATUS +DcApplyPacketFilter( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG PacketFilter); + +NDIS_STATUS +DcUpdateMulticastList( + _In_ PDC21X4_ADAPTER Adapter); + +VOID +DcPowerSave( + _In_ PDC21X4_ADAPTER Adapter, + _In_ BOOLEAN Enable); + +CODE_SEG("PAGE") +BOOLEAN +DcFindMiiPhy( + _In_ PDC21X4_ADAPTER Adapter); + +BOOLEAN +MiiWrite( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG PhyAddress, + _In_ ULONG RegAddress, + _In_ ULONG Data); + +BOOLEAN +MiiRead( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG PhyAddress, + _In_ ULONG RegAddress, + _Out_ PULONG Data); + +CODE_SEG("PAGE") +VOID +HpnaPhyInit( + _In_ PDC21X4_ADAPTER Adapter); + +VOID +NTAPI +DcTransmitTimeoutRecoveryWorker( + _In_ PNDIS_WORK_ITEM WorkItem, + _In_opt_ PVOID Context); + +NDIS_TIMER_FUNCTION MediaMonitor21040Dpc; +NDIS_TIMER_FUNCTION MediaMonitor21041Dpc; +NDIS_TIMER_FUNCTION MediaMonitor21140Dpc; +NDIS_TIMER_FUNCTION MediaMonitor21143Dpc; + +MEDIA_HANDLE_LINK_STATE_CHANGE MediaLinkStateChange21040; +MEDIA_HANDLE_LINK_STATE_CHANGE MediaLinkStateChange21041; +MEDIA_HANDLE_LINK_STATE_CHANGE MediaLinkStateChange21143; + +CODE_SEG("PAGE") +VOID +MediaInitMediaList( + _In_ PDC21X4_ADAPTER Adapter); + +CODE_SEG("PAGE") +VOID +MediaInitDefaultMedia( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG MediaNumber); + +VOID +MediaIndicateConnect( + _In_ PDC21X4_ADAPTER Adapter, + _In_ BOOLEAN LinkUp); + +VOID +MediaSelectMiiPort( + _In_ PDC21X4_ADAPTER Adapter, + _In_ BOOLEAN ResetPhy); + +VOID +MediaMiiSelect( + _In_ PDC21X4_ADAPTER Adapter); + +BOOLEAN +MediaMiiCheckLink( + _In_ PDC21X4_ADAPTER Adapter); + +VOID +MediaSiaSelect( + _In_ PDC21X4_ADAPTER Adapter); + +VOID +MediaGprSelect( + _In_ PDC21X4_ADAPTER Adapter); diff --git a/drivers/network/dd/dc21x4/dc21x4.rc b/drivers/network/dd/dc21x4/dc21x4.rc new file mode 100644 index 00000000000..1ecd5c02f7d --- /dev/null +++ b/drivers/network/dd/dc21x4/dc21x4.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "DC21x4 Ethernet Adapter Driver" +#define REACTOS_STR_INTERNAL_NAME "dc21x4" +#define REACTOS_STR_ORIGINAL_FILENAME "dc21x4.sys" +#include <reactos/version.rc> diff --git a/drivers/network/dd/dc21x4/dc21x4hw.h b/drivers/network/dd/dc21x4/dc21x4hw.h new file mode 100644 index 00000000000..fc53adc1b9d --- /dev/null +++ b/drivers/network/dd/dc21x4/dc21x4hw.h @@ -0,0 +1,597 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Hardware specific definitions + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +#pragma once + +typedef enum _DC_CHIP_TYPE +{ + DC21040, + DC21041, + DC21140, + DC21143, + DC21145, +} DC_CHIP_TYPE; + +/* + * PCI Vendor and Device IDs + */ +#define DC_DEV_DECCHIP_21040 0x00021011 +#define DC_DEV_DECCHIP_21041 0x00141011 +#define DC_DEV_DECCHIP_21140 0x00091011 +#define DC_DEV_INTEL_21143 0x00191011 +#define DC_DEV_INTEL_21145 0x00398086 + +#define DC_DESCRIPTOR_ALIGNMENT 4 +#define DC_SETUP_FRAME_ALIGNMENT 4 +#define DC_RECEIVE_BUFFER_ALIGNMENT 4 +#define DC_RECEIVE_BUFFER_SIZE_MULTIPLE 4 + +#define DC_IO_LENGTH 128 + +#define DC_SETUP_FRAME_SIZE 192 + +/* Multicast perfect filter */ +#define DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES 16 + +/* -1 for physical address and -1 for broadcast address */ +#define DC_SETUP_FRAME_ADDRESSES (16 - 2) + +/* Computed hash of FF:FF:FF:FF:FF:FF */ +#define DC_SETUP_FRAME_BROADCAST_HASH 0xFF + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define DC_SETUP_FRAME_ENTRY(Value) (Value) +#else +#define DC_SETUP_FRAME_ENTRY(Value) ((Value) << 16) +#endif + +#include <pshpack1.h> + +/* + * Transmit Buffer Descriptor + */ +typedef struct _DC_TBD +{ + ULONG Status; +#define DC_TBD_STATUS_DEFFERED 0x00000001 +#define DC_TBD_STATUS_UNDERFLOW 0x00000002 +#define DC_TBD_STATUS_LINK_FAIL 0x00000004 +#define DC_TBD_STATUS_COLLISIONS_MASK 0x00000078 +#define DC_TBD_STATUS_HEARTBEAT_FAIL 0x00000080 +#define DC_TBD_STATUS_RETRY_ERROR 0x00000100 +#define DC_TBD_STATUS_LATE_COLLISION 0x00000200 +#define DC_TBD_STATUS_NO_CARRIER 0x00000400 +#define DC_TBD_STATUS_CARRIER_LOST 0x00000800 +#define DC_TBD_STATUS_JABBER_TIMEOUT 0x00004000 +#define DC_TBD_STATUS_ERROR_SUMMARY 0x00008000 +#define DC_TBD_STATUS_OWNED 0x80000000 + +#define DC_TBD_STATUS_SETUP_FRAME 0x7FFFFFFF + +#define DC_TBD_STATUS_COLLISIONS_SHIFT 3 + + ULONG Control; +#define DC_TBD_CONTROL_LENGTH_MASK_1 0x000007FF +#define DC_TBD_CONTROL_LENGTH_MASK_2 0x003FF800 +#define DC_TBD_CONTROL_NO_PAD 0x00800000 +#define DC_TBD_CONTROL_CHAINED 0x01000000 +#define DC_TBD_CONTROL_END_OF_RING 0x02000000 +#define DC_TBD_CONTROL_NO_CRC 0x04000000 +#define DC_TBD_CONTROL_SETUP_FRAME 0x08000000 +#define DC_TBD_CONTROL_FIRST_FRAGMENT 0x20000000 +#define DC_TBD_CONTROL_LAST_FRAGMENT 0x40000000 +#define DC_TBD_CONTROL_REQUEST_INTERRUPT 0x80000000 +#define DC_TBD_CONTROL_PERFECT_FILTER 0x00000000 +#define DC_TBD_CONTROL_HASH_PERFECT_FILTER 0x00400000 +#define DC_TBD_CONTROL_INVERSE_FILTER 0x10000000 +#define DC_TBD_CONTROL_IMPERFECT_FILTER 0x10400000 + +#define DC_TBD_CONTROL_LENGTH_2_SHIFT 11 + + ULONG Address1; + ULONG Address2; +} DC_TBD, *PDC_TBD; + +C_ASSERT(sizeof(DC_TBD) == 16); + +/* + * Receive Buffer Descriptor + */ +typedef struct _DC_RBD +{ + ULONG Status; +#define DC_RBD_STATUS_OVERRUN 0x00000001 +#define DC_RBD_STATUS_CRC_ERROR 0x00000002 +#define DC_RBD_STATUS_DRIBBLE 0x00000004 +#define DC_RBD_STATUS_MII_ERROR 0x00000008 +#define DC_RBD_STATUS_WDT_EXPIRED 0x00000010 +#define DC_RBD_STATUS_FRAME_TYPE 0x00000020 +#define DC_RBD_STATUS_COLLISION_SEEN 0x00000040 +#define DC_RBD_STATUS_TOO_LONG 0x00000080 +#define DC_RBD_STATUS_LAST_DESCRIPTOR 0x00000100 +#define DC_RBD_STATUS_FIRST_DESCRIPTOR 0x00000200 +#define DC_RBD_STATUS_MULTICAST 0x00000400 +#define DC_RBD_STATUS_RUNT 0x00000800 +#define DC_RBD_STATUS_DATA_TYPE_MASK 0x00003000 +#define DC_RBD_STATUS_LENGTH_ERROR 0x00004000 +#define DC_RBD_STATUS_ERROR_SUMMARY 0x00008000 +#define DC_RBD_STATUS_FRAME_LENGTH_MASK 0x3FFF0000 +#define DC_RBD_STATUS_FILTERING_FAIL 0x40000000 +#define DC_RBD_STATUS_OWNED 0x80000000 + +#define DC_RBD_STATUS_FRAME_LENGTH_SHIFT 16 + + ULONG Control; +#define DC_RBD_CONTROL_BUFFER_LENGTH_MASK_1 0x000007FF +#define DC_RBD_CONTROL_BUFFER_LENGTH_MASK_2 0x003FF800 +#define DC_RBD_CONTROL_CHAINED 0x01000000 +#define DC_RBD_CONTROL_END_OF_RING 0x02000000 + + ULONG Address1; + ULONG Address2; +} DC_RBD, *PDC_RBD; + +C_ASSERT(sizeof(DC_RBD) == 16); + +#define DC_PATTERN_FILTERS 4 + +/* + * Wake-Up Filter Register Block + */ +typedef union _DC_PATTERN_FILTER_BLOCK +{ + struct + { + ULONG Mask[DC_PATTERN_FILTERS]; + + UCHAR Command[DC_PATTERN_FILTERS]; +#define DC_PATTERN_FILTER_CMD_ENABLE 0x01 +#define DC_PATTERN_FILTER_CMD_INVERSE_MODE 0x02 +#define DC_PATTERN_FILTER_CMD_ADD_PREV 0x04 +#define DC_PATTERN_FILTER_CMD_MULTICAST 0x08 + + UCHAR Offset[DC_PATTERN_FILTERS]; + USHORT Crc[DC_PATTERN_FILTERS]; + }; + ULONG AsULONG[8]; +} DC_PATTERN_FILTER_BLOCK, *PDC_PATTERN_FILTER_BLOCK; + +C_ASSERT(sizeof(DC_PATTERN_FILTER_BLOCK) == 32); + +#include <poppack.h> + +/* + * NIC Control and Status Registers + */ +typedef enum _DC_CSR +{ + DcCsr0_BusMode = 0x00, + DcCsr1_TxPoll = 0x08, + DcCsr1_WakeUpFilter = 0x08, + DcCsr2_RxPoll = 0x10, + DcCsr2_WakeUpControl = 0x10, + DcCsr3_RxRingAddress = 0x18, + DcCsr4_TxRingAddress = 0x20, + DcCsr5_Status = 0x28, + DcCsr6_OpMode = 0x30, + DcCsr7_IrqMask = 0x38, + DcCsr8_RxCounters = 0x40, + DcCsr9_SerialInterface = 0x48, + DcCsr10_BootRom = 0x50, + DcCsr11_FullDuplex = 0x58, + DcCsr11_Timer = 0x58, + DcCsr12_Gpio = 0x60, + DcCsr12_SiaStatus = 0x60, + DcCsr13_SiaConnectivity = 0x68, + DcCsr14_SiaTxRx = 0x70, + DcCsr15_SiaGeneral = 0x78, +} DC_CSR; + +/* + * CSR0 Bus Mode + */ +#define DC_BUS_MODE_SOFT_RESET 0x00000001 +#define DC_BUS_MODE_BUS_ARB 0x00000002 +#define DC_BUS_MODE_DESC_SKIP_LENGTH_MASK 0x0000007C +#define DC_BUS_MODE_BUFFERS_BIG_ENDIAN 0x00000080 +#define DC_BUS_MODE_BURST_LENGTH_MASK 0x00003F00 +#define DC_BUS_MODE_CACHE_ALIGNMENT_MASK 0x0000C000 +#define DC_BUS_MODE_DIAGNOSTIC_ADDRESS_SPACE 0x00010000 +#define DC_BUS_MODE_TX_POLL_MASK 0x000E0000 +#define DC_BUS_MODE_DESC_BIG_ENDIAN 0x00100000 +#define DC_BUS_MODE_READ_MULTIPLE 0x00200000 +#define DC_BUS_MODE_READ_LINE 0x00800000 +#define DC_BUS_MODE_WRITE_INVALIDATE 0x01000000 +#define DC_BUS_MODE_ON_NOW_UNLOCK 0x04000000 + +#define DC_BUS_MODE_BURST_LENGTH_NO_LIMIT 0x00000000 +#define DC_BUS_MODE_BURST_LENGTH_1 0x00000100 +#define DC_BUS_MODE_BURST_LENGTH_2 0x00000200 +#define DC_BUS_MODE_BURST_LENGTH_4 0x00000400 +#define DC_BUS_MODE_BURST_LENGTH_8 0x00000800 +#define DC_BUS_MODE_BURST_LENGTH_16 0x00001000 +#define DC_BUS_MODE_BURST_LENGTH_32 0x00002000 + +#define DC_BUS_MODE_CACHE_ALIGNMENT_NONE 0x00000000 +#define DC_BUS_MODE_CACHE_ALIGNMENT_8 0x00004000 +#define DC_BUS_MODE_CACHE_ALIGNMENT_16 0x00008000 +#define DC_BUS_MODE_CACHE_ALIGNMENT_32 0x0000C000 + +#define DC_BUS_MODE_TX_POLL_DISABLED 0x00000000 +#define DC_BUS_MODE_TX_POLL_1 0x00020000 +#define DC_BUS_MODE_TX_POLL_2 0x00040000 +#define DC_BUS_MODE_TX_POLL_3 0x00060000 +#define DC_BUS_MODE_TX_POLL_4 0x00080000 +#define DC_BUS_MODE_TX_POLL_5 0x000A0000 +#define DC_BUS_MODE_TX_POLL_6 0x000C0000 +#define DC_BUS_MODE_TX_POLL_7 0x000E0000 + +#define DC_BUS_MODE_DESC_SKIP_LENGTH_0 0x00000000 +#define DC_BUS_MODE_DESC_SKIP_LENGTH_1 0x00000004 +#define DC_BUS_MODE_DESC_SKIP_LENGTH_2 0x00000008 +#define DC_BUS_MODE_DESC_SKIP_LENGTH_4 0x00000010 +#define DC_BUS_MODE_DESC_SKIP_LENGTH_8 0x00000020 +#define DC_BUS_MODE_DESC_SKIP_LENGTH_16 0x00000040 +#define DC_BUS_MODE_DESC_SKIP_LENGTH_32 0x00000080 + +/* + * CSR1 Transmit Poll Demand + */ +#define DC_TX_POLL_DOORBELL 0x00000001 + +/* + * CSR2 Receive Poll Demand + */ +#define DC_RX_POLL_DOORBELL 0x00000001 + +/* + * CSR2 Wake Up Control + */ +#define DC_WAKE_UP_CONTROL_LINK_CHANGE 0x00000001 +#define DC_WAKE_UP_CONTROL_MAGIC_PACKET 0x00000002 +#define DC_WAKE_UP_CONTROL_PATTERN_MATCH 0x00000004 +#define DC_WAKE_UP_STATUS_LINK_CHANGE 0x00000010 +#define DC_WAKE_UP_STATUS_MAGIC_PACKET 0x00000020 +#define DC_WAKE_UP_STATUS_PATTERN_MATCH 0x00000040 +#define DC_WAKE_UP_CONTROL_GLOBAL_UNICAST 0x00000200 +#define DC_WAKE_UP_CONTROL_VLAN_ENABLE 0x00000800 +#define DC_WAKE_UP_CONTROL_VLAN_TYPE_MASK 0xFFFF0000 + +/* + * CSR5 Status, CSR7 Irq Mask + */ +#define DC_IRQ_TX_OK 0x00000001 +#define DC_IRQ_TX_STOPPED 0x00000002 +#define DC_IRQ_TX_NO_BUFFER 0x00000004 +#define DC_IRQ_TX_JABBER_TIMEOUT 0x00000008 +#define DC_IRQ_LINK_PASS 0x00000010 +#define DC_IRQ_TX_UNDERFLOW 0x00000020 +#define DC_IRQ_RX_OK 0x00000040 +#define DC_IRQ_RX_NO_BUFFER 0x00000080 +#define DC_IRQ_RX_STOPPED 0x00000100 +#define DC_IRQ_RX_WDT_TIMEOUT 0x00000200 +#define DC_IRQ_AUI 0x00000400 +#define DC_IRQ_TX_EARLY 0x00000400 +#define DC_IRQ_FD_FRAME_RECEIVED 0x00000800 +#define DC_IRQ_TIMER_TIMEOUT 0x00000800 +#define DC_IRQ_LINK_FAIL 0x00001000 +#define DC_IRQ_SYSTEM_ERROR 0x00002000 +#define DC_IRQ_RX_EARLY 0x00004000 +#define DC_IRQ_ABNORMAL_SUMMARY 0x00008000 +#define DC_IRQ_NORMAL_SUMMARY 0x00010000 +#define DC_STATUS_RX_STATE_MASK 0x000E0000 +#define DC_STATUS_TX_STATE_MASK 0x00700000 +#define DC_STATUS_SYSTEM_ERROR_MASK 0x03800000 +#define DC_IRQ_GPIO_PORT 0x04000000 +#define DC_IRQ_LINK_CHANGED 0x08000000 +#define DC_IRQ_HPNA_PHY 0x10000000 + +#define DC_STATUS_TX_STATE_STOPPED 0x00000000 +#define DC_STATUS_TX_STATE_FETCH 0x00100000 +#define DC_STATUS_TX_STATE_WAIT_FOR_END 0x00200000 +#define DC_STATUS_TX_STATE_READ 0x00300000 +#define DC_STATUS_TX_STATE_RESERVED 0x00400000 +#define DC_STATUS_TX_STATE_SETUP_PACKET 0x00500000 +#define DC_STATUS_TX_STATE_SUSPENDED 0x00600000 +#define DC_STATUS_TX_STATE_CLOSE 0x00700000 + +#define DC_STATUS_RX_STATE_STOPPED 0x00000000 +#define DC_STATUS_RX_STATE_FETCH 0x00020000 +#define DC_STATUS_RX_STATE_CHECK_END 0x00040000 +#define DC_STATUS_RX_STATE_WAIT_FOR_RCV 0x00060000 +#define DC_STATUS_RX_STATE_SUSPENDED 0x00080000 +#define DC_STATUS_RX_STATE_CLOSE_DESC 0x000A0000 +#define DC_STATUS_RX_STATE_FLUSH 0x000C0000 +#define DC_STATUS_RX_STATE_DEQUEUE 0x000E0000 + +#define DC_STATUS_SYSTEM_ERROR_PARITY 0x00000000 +#define DC_STATUS_SYSTEM_ERROR_MASTER_ABORT 0x00800000 +#define DC_STATUS_SYSTEM_ERROR_TARGET_ABORT 0x01000000 + +/* + * CSR6 Operation Mode + */ +#define DC_OPMODE_RX_HASH_PERFECT_FILT 0x00000001 +#define DC_OPMODE_RX_ENABLE 0x00000002 +#define DC_OPMODE_RX_HASH_ONLY_FILT 0x00000004 +#define DC_OPMODE_RX_RUNTS 0x00000008 +#define DC_OPMODE_RX_INVERSE_FILT 0x00000010 +#define DC_OPMODE_BACKOFF_COUNTER 0x00000020 +#define DC_OPMODE_RX_PROMISCUOUS 0x00000040 +#define DC_OPMODE_RX_ALL_MULTICAST 0x00000080 +#define DC_OPMODE_FKD 0x00000100 +#define DC_OPMODE_FULL_DUPLEX 0x00000200 +#define DC_OPMODE_LOOPBACK_MASK 0x00000C00 +#define DC_OPMODE_FORCE_COLLISIONS 0x00001000 +#define DC_OPMODE_TX_ENABLE 0x00002000 +#define DC_OPMODE_TX_THRESHOLD_CTRL_MASK 0x0000C000 +#define DC_OPMODE_TX_BACK_PRESSURE 0x00010000 +#define DC_OPMODE_TX_CAPTURE_EFFECT 0x00020000 +#define DC_OPMODE_PORT_SELECT 0x00040000 +#define DC_OPMODE_PORT_HEARTBEAT_DISABLE 0x00080000 +#define DC_OPMODE_STORE_AND_FORWARD 0x00200000 +#define DC_OPMODE_PORT_XMIT_10 0x00400000 +#define DC_OPMODE_PORT_PCS 0x00800000 +#define DC_OPMODE_PORT_SCRAMBLER 0x01000000 +#define DC_OPMODE_PORT_ALWAYS 0x02000000 +#define DC_OPMODE_ADDR_LSB_IGNORE 0x04000000 +#define DC_OPMODE_RX_RECEIVE_ALL 0x40000000 +#define DC_OPMODE_TX_SPECIAL_CAPTURE_EFFECT 0x80000000 + +#define DC_OPMODE_LOOPBACK_NORMAL 0x00000000 +#define DC_OPMODE_LOOPBACK_INTERNAL 0x00000400 +#define DC_OPMODE_LOOPBACK_EXTERNAL 0x00000800 + +#define DC_OPMODE_TX_THRESHOLD_LEVEL 0x00004000 +#define DC_OPMODE_TX_THRESHOLD_MAX 0x0000C000 + +#define DC_OPMODE_MEDIA_MASK ( \ + DC_OPMODE_TX_THRESHOLD_CTRL_MASK | \ + DC_OPMODE_LOOPBACK_MASK | \ + DC_OPMODE_FULL_DUPLEX | \ + DC_OPMODE_PORT_SELECT | \ + DC_OPMODE_PORT_HEARTBEAT_DISABLE | \ + DC_OPMODE_PORT_XMIT_10 | \ + DC_OPMODE_PORT_PCS | \ + DC_OPMODE_PORT_SCRAMBLER) + +/* + * CSR8 Receive Counters + */ +#define DC_COUNTER_RX_NO_BUFFER_MASK 0x0001FFFF +#define DC_COUNTER_RX_OVERFLOW_MASK 0x1FFE0000 + +#define DC_COUNTER_RX_OVERFLOW_SHIFT 17 + +/* + * CSR9 Serial Interface + */ +#define DC_SERIAL_EE_CS 0x00000001 +#define DC_SERIAL_EE_SK 0x00000002 +#define DC_SERIAL_EE_DI 0x00000004 +#define DC_SERIAL_EE_DO 0x00000008 +#define DC_SERIAL_EE_REG 0x00000400 +#define DC_SERIAL_EE_SR 0x00000800 +#define DC_SERIAL_EE_WR 0x00002000 +#define DC_SERIAL_EE_RD 0x00004000 +#define DC_SERIAL_EE_MOD 0x00008000 +#define DC_SERIAL_MII_MDC 0x00010000 +#define DC_SERIAL_MII_MDO 0x00020000 +#define DC_SERIAL_MII_MII 0x00040000 +#define DC_SERIAL_MII_MDI 0x00080000 +#define DC_SERIAL_EAR_DN 0x80000000 +#define DC_SERIAL_EAR_DT 0x000000FF +#define DC_SERIAL_SPI_CS 0x00100000 +#define DC_SERIAL_SPI_SK 0x00200000 +#define DC_SERIAL_SPI_DI 0x00400000 +#define DC_SERIAL_SPI_DO 0x00800000 + +#define DC_SERIAL_EE_DI_SHIFT 2 +#define DC_SERIAL_EE_DO_SHIFT 3 +#define DC_SERIAL_MII_MDO_SHIFT 17 +#define DC_SERIAL_MII_MDI_SHIFT 19 +#define DC_SERIAL_SPI_DI_SHIFT 22 +#define DC_SERIAL_SPI_DO_SHIFT 23 + +/* + * CSR11 Timer + */ +#define DC_TIMER_VALUE_MASK 0x0000FFFF +#define DC_TIMER_CONTINUOUS 0x00010000 +#define DC_TIMER_RX_NUMBER_MASK 0x000E0000 +#define DC_TIMER_RX_TIMER_MASK 0x00F00000 +#define DC_TIMER_TX_NUMBER_MASK 0x07000000 +#define DC_TIMER_TX_TIMER_MASK 0x78000000 +#define DC_TIMER_CYCLE_SIZE 0x80000000 + +#define DC_TIMER_RX_NUMBER_SHIFT 17 +#define DC_TIMER_RX_TIMER_SHIFT 20 +#define DC_TIMER_TX_NUMBER_SHIFT 24 +#define DC_TIMER_TX_TIMER_SHIFT 27 + +/* + * CSR12 SIA Status + */ +#define DC_SIA_STATUS_MII_RECEIVE_ACTIVITY 0x00000001 +#define DC_SIA_STATUS_NETWORK_CONNECTION_ERROR 0x00000002 +#define DC_SIA_STATUS_100T_LINK_FAIL 0x00000002 +#define DC_SIA_STATUS_10T_LINK_FAIL 0x00000004 +#define DC_SIA_STATUS_SELECTED_PORT_ACTIVITY 0x00000100 +#define DC_SIA_STATUS_AUI_ACTIVITY 0x00000100 +#define DC_SIA_STATUS_HPNA_ACTIVITY 0x00000100 +#define DC_SIA_STATUS_NONSEL_PORT_ACTIVITY 0x00000200 +#define DC_SIA_STATUS_10T_ACTIVITY 0x00000200 +#define DC_SIA_STATUS_NSN 0x00000400 +#define DC_SIA_STATUS_TX_REMOTE_FAULT 0x00000800 +#define DC_SIA_STATUS_ANS_MASK 0x00007000 +#define DC_SIA_STATUS_LP_AUTONED_SUPPORTED 0x00008000 +#define DC_SIA_STATUS_LP_CODE_WORD_MASK 0xFFFF0000 + +#define DC_SIA_STATUS_ANS_AUTONEG_DISABLED 0x00000000 +#define DC_SIA_STATUS_ANS_TX_DISABLE 0x00001000 +#define DC_SIA_STATUS_ANS_ABILITY_DETECT 0x00002000 +#define DC_SIA_STATUS_ANS_ACK_DETECT 0x00003000 +#define DC_SIA_STATUS_ANS_ACK_COMPLETE 0x00004000 +#define DC_SIA_STATUS_ANS_AUTONEG_COMPLETE 0x00005000 +#define DC_SIA_STATUS_ANS_LINK_CHECK 0x00006000 + +#define DC_SIA_STATUS_LP_CODE_WORD_SHIFT 16 + +#define DC_GPIO_CONTROL 0x100 + +/* + * CSR13 SIA Connectivity + */ +#define DC_SIA_CONN_RESET 0x00000000 +#define DC_SIA_CONN_HPNA 0x00000008 + +/* + * CSR14 SIA Transmit and Receive + */ +#define DC_SIA_TXRX_ENCODER 0x00000001 +#define DC_SIA_TXRX_LOOPBACK 0x00000002 +#define DC_SIA_TXRX_DRIVER 0x00000004 +#define DC_SIA_TXRX_LINK_PULSE 0x00000008 +#define DC_SIA_TXRX_COMPENSATION 0x00000030 +#define DC_SIA_TXRX_ADV_10T_HD 0x00000040 +#define DC_SIA_TXRX_AUTONEG 0x00000080 +#define DC_SIA_TXRX_RX_SQUELCH 0x00000100 +#define DC_SIA_TXRX_COLLISION_SQUELCH 0x00000200 +#define DC_SIA_TXRX_COLLISION_DETECT 0x00000400 +#define DC_SIA_TXRX_HEARTBEAT 0x00000800 +#define DC_SIA_TXRX_LINK_TEST 0x00001000 +#define DC_SIA_TXRX_AUTOPOLARITY 0x00002000 +#define DC_SIA_TXRX_SET_POLARITY_PLUS 0x00004000 +#define DC_SIA_TXRX_10T_AUTOSENSE 0x00008000 +#define DC_SIA_TXRX_ADV_100TX_HD 0x00010000 +#define DC_SIA_TXRX_ADV_100TX_FD 0x00020000 +#define DC_SIA_TXRX_ADV_100T4 0x00040000 + +/* + * CSR15 SIA and GPIO + */ +#define DC_SIA_GENERAL_JABBER_DISABLE 0x00000001 +#define DC_SIA_GENERAL_HOST_UNJAB 0x00000002 +#define DC_SIA_GENERAL_JABBER_CLOCK 0x00000004 +#define DC_SIA_GENERAL_AUI_BNC_MODE 0x00000008 +#define DC_SIA_GENERAL_RX_WDT_DISABLE 0x00000010 +#define DC_SIA_GENERAL_RX_WDT_RELEASE 0x00000020 +#define DC_SIA_GENERAL_LINK_EXTEND 0x00000800 +#define DC_SIA_GENERAL_RX_MAGIC_PACKET 0x00004000 +#define DC_SIA_GENERAL_HCKR 0x00008000 +#define DC_SIA_GENERAL_GPIO_MASK 0x000F0000 +#define DC_SIA_GENERAL_LGS3 0x00100000 +#define DC_SIA_GENERAL_LGS2 0x00200000 +#define DC_SIA_GENERAL_LGS1 0x00400000 +#define DC_SIA_GENERAL_LGS0 0x00800000 +#define DC_SIA_GENERAL_GEI0 0x01000000 +#define DC_SIA_GENERAL_GEI1 0x02000000 +#define DC_SIA_GENERAL_RECEIVE_MATCH 0x04000000 +#define DC_SIA_GENERAL_CONTROL_WRITE 0x08000000 +#define DC_SIA_GENERAL_GI0 0x10000000 +#define DC_SIA_GENERAL_GI1 0x20000000 +#define DC_SIA_GENERAL_IRQ_RX_MATCH 0x40000000 + +#define DC_RBD_STATUS_INVALID \ + (DC_RBD_STATUS_OVERRUN | \ + DC_RBD_STATUS_CRC_ERROR | \ + DC_RBD_STATUS_WDT_EXPIRED | \ + DC_RBD_STATUS_COLLISION_SEEN | \ + DC_RBD_STATUS_TOO_LONG | \ + DC_RBD_STATUS_RUNT | \ + DC_RBD_STATUS_LENGTH_ERROR) + +#define DC_GENERIC_IRQ_MASK \ + (DC_IRQ_TX_OK | DC_IRQ_TX_STOPPED | DC_IRQ_TX_JABBER_TIMEOUT | \ + DC_IRQ_RX_OK | DC_IRQ_TX_UNDERFLOW | \ + DC_IRQ_RX_STOPPED | \ + DC_IRQ_SYSTEM_ERROR | DC_IRQ_ABNORMAL_SUMMARY | DC_IRQ_NORMAL_SUMMARY) + +/* Errata: The programming guide incorrectly stated that CSR13 must be set to 0x30480009 */ +#define DC_HPNA_ANALOG_CTRL 0x708A0000 + +/* + * PCI Configuration Registers + */ +#define DC_PCI_DEVICE_CONFIG 0x40 +#define DC_PCI_DEVICE_CONFIG_SNOOZE 0x40000000 +#define DC_PCI_DEVICE_CONFIG_SLEEP 0x80000000 + +/* + * SPI Interface + */ +#define DC_SPI_BYTE_WRITE_OPERATION 2 +#define DC_SPI_BYTE_READ_OPERATION 3 +#define DC_SPI_CLEAR_WRITE_ENABLE 4 +#define DC_SPI_SET_WRITE_ENABLE 6 + +/* + * HomePNA PHY Registers + */ +#define HPNA_CONTROL_LOW 0x00 +#define HPNA_CONTROL_HIGH 0x01 +#define HPNA_NOISE 0x10 +#define HPNA_NOISE_FLOOR 0x12 +#define HPNA_NOISE_CEILING 0x13 +#define HPNA_NOISE_ATTACK 0x14 + +/* + * MDIO Protocol (IEEE 802.3) + */ +#define MDIO_START 0x01 +#define MDIO_WRITE 0x01 +#define MDIO_READ 0x02 +#define MDIO_TA 0x02 +#define MDIO_PREAMBLE 0xFFFFFFFF + +#define MII_MAX_PHY_ADDRESSES 32 + +/* + * PHY register definitions (IEEE 802.3) + */ +#define MII_CONTROL 0x00 +#define MII_CR_COLLISION_TEST 0x0080 +#define MII_CR_FULL_DUPLEX 0x0100 +#define MII_CR_AUTONEG_RESTART 0x0200 +#define MII_CR_ISOLATE 0x0400 +#define MII_CR_POWER_DOWN 0x0800 +#define MII_CR_AUTONEG 0x1000 +#define MII_CR_SPEED_SELECTION 0x2000 +#define MII_CR_LOOPBACK 0x4000 +#define MII_CR_RESET 0x8000 +#define MII_STATUS 0x01 +#define MII_SR_LINK_STATUS 0x0004 +#define MII_SR_AUTONEG_COMPLETE 0x0020 +#define MII_PHY_ID1 0x02 +#define MII_PHY_ID2 0x03 +#define MII_AUTONEG_ADVERTISE 0x04 +#define MII_ADV_CSMA 0x0001 +#define MII_ADV_10T_HD 0x0020 +#define MII_ADV_10T_FD 0x0040 +#define MII_ADV_100T_HD 0x0080 +#define MII_ADV_100T_FD 0x0100 +#define MII_ADV_100T4 0x0200 +#define MII_ADV_PAUSE_SYM 0x0400 +#define MII_ADV_PAUSE_ASYM 0x0800 +#define MII_AUTONEG_LINK_PARTNER 0x05 +#define MII_LP_10T_HD 0x0020 +#define MII_LP_10T_FD 0x0040 +#define MII_LP_100T_HD 0x0080 +#define MII_LP_100T_FD 0x0100 +#define MII_LP_100T4 0x0200 +#define MII_LP_PAUSE_SYM 0x0400 +#define MII_LP_PAUSE_ASYM 0x0800 +#define MII_AUTONEG_EXPANSION 0x06 +#define MII_EXP_LP_AUTONEG 0x0001 +#define MII_MASTER_SLAVE_CONTROL 0x09 +#define MII_MS_CR_1000T_HD 0x0100 +#define MII_MS_CR_1000T_FD 0x0200 +#define MII_MASTER_SLAVE_STATUS 0x0A +#define MII_MS_SR_1000T_FD 0x0800 + +#define MII_ADV_100 \ + (MII_ADV_100T_HD | MII_ADV_100T_FD | MII_ADV_100T4) diff --git a/drivers/network/dd/dc21x4/debug.c b/drivers/network/dd/dc21x4/debug.c new file mode 100644 index 00000000000..3dc9e5f073f --- /dev/null +++ b/drivers/network/dd/dc21x4/debug.c @@ -0,0 +1,70 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Debug routines + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +/* INCLUDES *******************************************************************/ + +#include "dc21x4.h" + +/* GLOBALS ********************************************************************/ + +static PCSTR MediaName[MEDIA_MAX] = +{ + "10Base-T", + "10Base-2 (BNC)", + "10Base-5 (AUI)", + "100Base-TX HD", + "10Base-T FD", + "100Base-TX FD", + "100Base-T4", + "100Base-FX HD", + "100Base-FX FD", + "HomePNA", + "MII", +}; + +/* FUNCTIONS ******************************************************************/ + +PCSTR +MediaNumber2Str( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG MediaNumber) +{ + switch (MediaNumber) + { + case MEDIA_100TX_HD: + { + if (Adapter->ChipType == DC21041) + return "10Base-T HD"; + break; + } + + default: + break; + } + + ASSERT(MediaNumber < MEDIA_MAX); + + return MediaName[MediaNumber]; +} + +PCSTR +DcDbgBusError( + _In_ ULONG InterruptStatus) +{ + switch (InterruptStatus & DC_STATUS_SYSTEM_ERROR_MASK) + { + case DC_STATUS_SYSTEM_ERROR_PARITY: + return "Parity Error"; + case DC_STATUS_SYSTEM_ERROR_MASTER_ABORT: + return "Master Abort"; + case DC_STATUS_SYSTEM_ERROR_TARGET_ABORT: + return "Target Abort"; + + default: + return "<unknown>"; + } +} diff --git a/drivers/network/dd/dc21x4/debug.h b/drivers/network/dd/dc21x4/debug.h new file mode 100644 index 00000000000..f1a4e178de3 --- /dev/null +++ b/drivers/network/dd/dc21x4/debug.h @@ -0,0 +1,96 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Debug support header file + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +#pragma once + +#ifndef __RELFILE__ +#define __RELFILE__ __FILE__ +#endif + +#if DBG + +// #define DEBUG_TRACE +// #define DEBUG_INFO +#define DEBUG_INFO_VERB +#define DEBUG_WARN +#define DEBUG_ERR + +#ifdef DEBUG_TRACE +#define TRACE(fmt, ...) \ + do { \ + if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + +#else +#define TRACE +#endif + +#ifdef DEBUG_INFO +#define INFO(fmt, ...) \ + do { \ + if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + +#else +#define INFO +#endif + +#ifdef DEBUG_INFO_VERB +#define INFO_VERB(fmt, ...) \ + do { \ + if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + +#else +#define INFO_VERB +#endif + +#ifdef DEBUG_WARN +#define WARN(fmt, ...) \ + do { \ + if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + +#else +#define WARN +#endif + +#ifdef DEBUG_ERR +#define ERR(fmt, ...) \ + do { \ + if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + +#else +#define ERR +#endif + +PCSTR +MediaNumber2Str( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG MediaNumber); + +PCSTR +DcDbgBusError( + _In_ ULONG InterruptStatus); + +#else + +#define TRACE +#define INFO +#define INFO_VERB +#define WARN +#define ERR +#define MediaNumber2Str +#define DcDbgBusError + +#endif diff --git a/drivers/network/dd/dc21x4/eeprom.c b/drivers/network/dd/dc21x4/eeprom.c new file mode 100644 index 00000000000..6937a5723df --- /dev/null +++ b/drivers/network/dd/dc21x4/eeprom.c @@ -0,0 +1,1525 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: EEPROM manipulation and parsing + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +/* INCLUDES *******************************************************************/ + +#include "dc21x4.h" + +#include <debug.h> + +/* GLOBALS ********************************************************************/ + +#define SROM_READ(Adapter, Data) \ + do { \ + *Data = DC_READ((Adapter), DcCsr9_SerialInterface); \ + NdisStallExecution(10); \ + } while (0) + +#define SROM_WRITE(Adapter, Value) \ + do { \ + DC_WRITE((Adapter), DcCsr9_SerialInterface, Value); \ + NdisStallExecution(10); \ + } while (0) + +extern DC_PG_DATA DC_SROM_REPAIR_ENTRY SRompRepairData[]; + +LIST_ENTRY SRompAdapterList; + +_Interlocked_ +static volatile LONG SRompAdapterLock = 0; + +/* PRIVATE FUNCTIONS **********************************************************/ + +static +CODE_SEG("PAGE") +VOID +SRomAcquireListMutex(VOID) +{ + PAGED_CODE(); + + while (_InterlockedCompareExchange(&SRompAdapterLock, 1, 0)) + { + NdisMSleep(10); + } +} + +static inline +CODE_SEG("PAGE") +VOID +SRomReleaseListMutex(VOID) +{ + PAGED_CODE(); + + _InterlockedDecrement(&SRompAdapterLock); +} + +static +CODE_SEG("PAGE") +BOOLEAN +SRomIsAdapterInList( + _In_ PDC21X4_ADAPTER Adapter, + _In_ BOOLEAN SearchForMaster, + _Out_opt_ PDC_SROM_ENTRY* FoundEntry) +{ + PLIST_ENTRY PrevEntry; + PDC_SROM_ENTRY SRomEntry; + + PAGED_CODE(); + + /* Loop the adapter list backwards */ + for (PrevEntry = (&SRompAdapterList)->Blink; + PrevEntry != &SRompAdapterList; + PrevEntry = PrevEntry->Blink) + { + SRomEntry = CONTAINING_RECORD(PrevEntry, DC_SROM_ENTRY, ListEntry); + + if ((SRomEntry->ChipType == Adapter->ChipType) && + (SRomEntry->BusNumber == Adapter->BusNumber) && + (!SearchForMaster || (SRomEntry->DeviceNumber == Adapter->DeviceNumber))) + { + if (FoundEntry) + *FoundEntry = SRomEntry; + + return TRUE; + } + } + + return FALSE; +} + +static +CODE_SEG("PAGE") +BOOLEAN +SRomRegisterMasterAdapter( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PDC_SROM_ENTRY SRomEntry) +{ + BOOLEAN Success; + + PAGED_CODE(); + + SRomAcquireListMutex(); + + /* Check if board is already registered */ + if (SRomIsAdapterInList(Adapter, TRUE, NULL)) + { + Success = FALSE; + goto Exit; + } + + Adapter->SRomEntry = SRomEntry; + + SRomEntry->ChipType = Adapter->ChipType; + SRomEntry->BusNumber = Adapter->BusNumber; + SRomEntry->DeviceNumber = Adapter->DeviceNumber; + SRomEntry->InterruptLevel = Adapter->InterruptLevel; + SRomEntry->InterruptVector = Adapter->InterruptVector; + + /* Register the port */ + SRomEntry->DeviceBitmap |= 1 << Adapter->DeviceNumber; + + /* + * On some multiport boards only the first port contains an EEPROM. + * We put their references to the global adapter list. + */ + InsertTailList(&SRompAdapterList, &SRomEntry->ListEntry); + Success = TRUE; + +Exit: + SRomReleaseListMutex(); + + return Success; +} + +static +CODE_SEG("PAGE") +BOOLEAN +SRomFindMasterAdapter( + _In_ PDC21X4_ADAPTER Adapter, + _Out_ PDC_SROM_ENTRY* FoundEntry) +{ + PDC_SROM_ENTRY SRomEntry; + ULONG i; + BOOLEAN Found; + + PAGED_CODE(); + + SRomAcquireListMutex(); + + if (!SRomIsAdapterInList(Adapter, FALSE, &SRomEntry)) + { + Found = FALSE; + goto Exit; + } + + Adapter->SRomEntry = SRomEntry; + + /* Register the port */ + SRomEntry->DeviceBitmap |= 1 << Adapter->DeviceNumber; + + /* + * Determine the port index that should be used in order to + * (possibly) update the base MAC address. + */ + for (i = 0; i < PCI_MAX_DEVICES; ++i) + { + if (i == Adapter->DeviceNumber) + break; + + if (SRomEntry->DeviceBitmap & (1 << i)) + ++Adapter->ControllerIndex; + } + + /* + * On a multiport board there can be up to 4 ports + * connected through a 21050 or 21152 PCI-to-PCI Bridge. + * These boards share a single IRQ line between all of the chips. + * Some BIOSes incorrectly assign different IRQs to the different ports. + */ + Adapter->InterruptLevel = SRomEntry->InterruptLevel; + Adapter->InterruptVector = SRomEntry->InterruptVector; + + WARN("EEPROM is missing on controller %u, using image from the master at %u:%u\n", + Adapter->DeviceNumber, + SRomEntry->BusNumber, + SRomEntry->DeviceNumber); + + *FoundEntry = SRomEntry; + Found = TRUE; + +Exit: + SRomReleaseListMutex(); + + return Found; +} + +static +CODE_SEG("PAGE") +BOOLEAN +SRomIsEmpty( + _In_reads_bytes_(Length) const VOID* Buffer, + _In_ ULONG Length) +{ + const UCHAR* Data = Buffer; + const UCHAR FirstByte = Data[0]; + ULONG i; + + PAGED_CODE(); + + for (i = 1; i < Length; ++i) + { + if (FirstByte != Data[i]) + return FALSE; + } + + return TRUE; +} + +static +CODE_SEG("PAGE") +VOID +SRomNWayAdvertise( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG MediaCode) +{ + PAGED_CODE(); + + switch (MediaCode) + { + case MEDIA_10T: + Adapter->SymAdvertising |= MII_ADV_10T_HD; + break; + case MEDIA_10T_FD: + Adapter->SymAdvertising |= MII_ADV_10T_FD; + break; + case MEDIA_100TX_HD: + Adapter->SymAdvertising |= MII_ADV_100T_HD; + break; + case MEDIA_100TX_FD: + Adapter->SymAdvertising |= MII_ADV_100T_FD; + break; + case MEDIA_100T4: + Adapter->SymAdvertising |= MII_ADV_100T4; + break; + + default: + break; + } +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomDecodeBlockGpr( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRomEnd, + _In_ PUCHAR BlockData) +{ + PDC_MEDIA Media; + ULONG MediaCode, OpMode; + USHORT Command; + + PAGED_CODE(); + + if (BlockData > (SRomEnd - 4)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + MediaCode = SRomGetMediaCode(*BlockData++); + if (MediaCode > SROM_MEDIA_MAX) + { + WARN("Unknown media code %u\n", MediaCode); + return NDIS_STATUS_SUCCESS; + } + Adapter->MediaBitmap |= 1 << MediaCode; + + Media = &Adapter->Media[MediaCode]; + + Media->GpioData = *BlockData++; + + Command = DcRetrieveWord(BlockData); + + OpMode = Media->OpMode; + OpMode &= ~SROM_OPMODE_MASK; + OpMode |= SRomCommandToOpMode(Command); + Media->OpMode = OpMode; + + if (SRomMediaHasActivityIndicator(Command)) + { + Media->LinkMask = SRomMediaGetSenseMask(Command); + } + if (SRomMediaActivityIsActiveLow(Command)) + { + Media->Polarity = 0xFFFFFFFF; + } + + INFO("GPR #%u %s, Command %04lx, Data %02lx\n", + MediaCode, + MediaNumber2Str(Adapter, MediaCode), + Command, + Media->GpioData); + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomDecodeBlockMii( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRomEnd, + _In_ PUCHAR BlockData, + _In_ BOOLEAN IsOldVersion) +{ + PDC_MII_MEDIA Media; + ULONG i, Bytes, Offset; + UCHAR PhyNumber, StreamLength, InterruptInfo; + USHORT Capabilities, Fdx, Ttm; + + PAGED_CODE(); + + if (BlockData > (SRomEnd - 2)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + PhyNumber = *BlockData++; + + /* + * Even though the SROM specification allows several + * PHY devices to be connected to the same chip on a board, + * most if not all boards never use more than 1 MII PHY device. + */ + if (Adapter->Features & DC_HAS_MII) + { + WARN("Unsupported PHY %u\n", PhyNumber); + return NDIS_STATUS_SUCCESS; + } + + Media = &Adapter->MiiMedia; + + /* + * PHY selection sequence + */ + + StreamLength = *BlockData++; + if (StreamLength > SROM_MAX_STREAM_REGS) + { + WARN("Too much registers %u\n", StreamLength); + return NDIS_STATUS_SUCCESS; + } + + Bytes = StreamLength; + if (!IsOldVersion) + { + /* In words */ + Bytes *= 2; + } + if ((BlockData + Bytes) > (SRomEnd - 1)) + { + return NDIS_STATUS_BUFFER_OVERFLOW; + } + + Media->SetupStreamLength = StreamLength; + + /* Check if we already have the GPIO direction data */ + if (Media->SetupStream[0] != 0) + { + Offset = 1; + ++Media->SetupStreamLength; + } + else + { + Offset = 0; + } + + for (i = 0; i < StreamLength; ++i) + { + if (IsOldVersion) + { + Media->SetupStream[i + Offset] = *BlockData++; + } + else + { + Media->SetupStream[i + Offset] = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + } + } + + /* + * PHY reset sequence + */ + + if (BlockData > (SRomEnd - 1)) + { + return NDIS_STATUS_BUFFER_OVERFLOW; + } + + StreamLength = *BlockData++; + if (StreamLength > SROM_MAX_STREAM_REGS) + { + WARN("Too much registers %u\n", StreamLength); + return NDIS_STATUS_SUCCESS; + } + + Bytes = StreamLength; + if (!IsOldVersion) + { + /* In words */ + Bytes *= 2; + } + if ((BlockData + Bytes) > (SRomEnd - 1)) + { + return NDIS_STATUS_BUFFER_OVERFLOW; + } + + Media->ResetStreamLength = StreamLength; + + for (i = 0; i < StreamLength; ++i) + { + if (IsOldVersion) + { + Media->ResetStream[i] = *BlockData++; + } + else + { + Media->ResetStream[i] = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + } + } + + /* + * MII data + */ + + Bytes = 4 * sizeof(USHORT); + if (!IsOldVersion) + { + Bytes += 1; + } + if (BlockData > (SRomEnd - Bytes)) + { + return NDIS_STATUS_BUFFER_OVERFLOW; + } + + Capabilities = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Media->Advertising = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Fdx = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Ttm = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + InterruptInfo = IsOldVersion ? 0 : *BlockData; + + Adapter->Features |= DC_HAS_MII; + + INFO("MII #%u, Caps %04lx, Adv %04lx, Fdx %04lx, Ttm %04lx, Int %02x\n", + PhyNumber, + Capabilities, + Media->Advertising, + Fdx, + Ttm, + InterruptInfo); + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomDecodeBlockSia( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRomEnd, + _In_ PUCHAR BlockData) +{ + PDC_MEDIA Media; + UCHAR BlockStart; + ULONG MediaCode; + BOOLEAN HasExtendedData; + + PAGED_CODE(); + + if (BlockData > (SRomEnd - 1)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + BlockStart = *BlockData++; + + HasExtendedData = SRomBlockHasExtendedData(BlockStart); + if (BlockData > (SRomEnd - (HasExtendedData ? 10 : 4))) + return NDIS_STATUS_BUFFER_OVERFLOW; + + MediaCode = SRomGetMediaCode(BlockStart); + if (MediaCode > SROM_MEDIA_MAX && MediaCode != SROM_MEDIA_HMR) + { + WARN("Unknown media code %u\n", MediaCode); + return NDIS_STATUS_SUCCESS; + } + + /* TODO: There were a few 21143-based boards with HMR media */ + if ((MediaCode == SROM_MEDIA_HMR) && (Adapter->ChipType != DC21145)) + { + ERR("FIXME: 21143 HMR is not supported yet\n"); + return NDIS_STATUS_SUCCESS; + } + + /* Map the code to our internal value */ + if (MediaCode == SROM_MEDIA_HMR) + { + MediaCode = MEDIA_HMR; + } + + Adapter->MediaBitmap |= 1 << MediaCode; + + Media = &Adapter->Media[MediaCode]; + + if (HasExtendedData) + { + Media->Csr13 = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Media->Csr14 = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Media->Csr15 = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + } + + Media->GpioCtrl = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Media->GpioData = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + SRomNWayAdvertise(Adapter, MediaCode); + + INFO("SIA #%u %s, %sCSR13 %04lx CSR14 %04lx CSR15 %04lx, " + "Ctrl %04lx, Data %04lx\n", + MediaCode, + MediaNumber2Str(Adapter, MediaCode), + HasExtendedData ? "EXT " : "", + Media->Csr13, + Media->Csr14, + Media->Csr15, + Media->GpioCtrl, + Media->GpioData); + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomDecodeBlockSym( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRomEnd, + _In_ PUCHAR BlockData) +{ + PDC_MEDIA Media; + ULONG MediaCode, OpMode; + USHORT Command; + + PAGED_CODE(); + + if (BlockData > (SRomEnd - 7)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + MediaCode = SRomGetMediaCode(*BlockData++); + if (MediaCode > SROM_MEDIA_MAX) + { + WARN("Unknown media code %u\n", MediaCode); + return NDIS_STATUS_SUCCESS; + } + Adapter->MediaBitmap |= 1 << MediaCode; + + Media = &Adapter->Media[MediaCode]; + + Media->GpioCtrl = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Media->GpioData = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Command = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + OpMode = Media->OpMode; + OpMode &= ~SROM_OPMODE_MASK; + OpMode |= SRomCommandToOpMode(Command); + Media->OpMode = OpMode; + + SRomNWayAdvertise(Adapter, MediaCode); + + INFO("SYM #%u %s, Command %04lx, Ctrl %04lx, Data %04lx\n", + MediaCode, + MediaNumber2Str(Adapter, MediaCode), + Command, + Media->GpioCtrl, + Media->GpioData); + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomDecodeBlockReset( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRomEnd, + _In_ PUCHAR BlockData) +{ + UCHAR i, StreamLength; + + PAGED_CODE(); + + if (BlockData > (SRomEnd - 1)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + StreamLength = *BlockData++; + if (StreamLength > SROM_MAX_STREAM_REGS) + { + WARN("Too much registers %u\n", StreamLength); + return NDIS_STATUS_SUCCESS; + } + + if ((BlockData + StreamLength * 2) > (SRomEnd - 1)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + Adapter->ResetStreamLength = StreamLength; + + for (i = 0; i < StreamLength; ++i) + { + Adapter->ResetStream[i] = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + } + + INFO("RESET, length %u\n", StreamLength); + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomDecodeBlockHmr( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRomEnd, + _In_ PUCHAR BlockData, + _In_ UCHAR BlockLength) +{ + ULONG Offset, ExtraData, i; + + PAGED_CODE(); + + if (BlockData > (SRomEnd - (2 + 6))) + return NDIS_STATUS_BUFFER_OVERFLOW; + + Adapter->AnalogControl = DcRetrieveWord(BlockData) << 16; + BlockData += sizeof(USHORT); + + Adapter->HpnaRegister[HPNA_CONTROL_LOW] = *BlockData++; + Adapter->HpnaRegister[HPNA_CONTROL_HIGH] = *BlockData++; + Adapter->HpnaRegister[HPNA_NOISE] = *BlockData++; + Adapter->HpnaRegister[HPNA_NOISE_FLOOR] = *BlockData++; + Adapter->HpnaRegister[HPNA_NOISE_CEILING] = *BlockData++; + Adapter->HpnaRegister[HPNA_NOISE_ATTACK] = *BlockData++; + Adapter->HpnaInitBitmap |= ((1 << HPNA_CONTROL_LOW) | + (1 << HPNA_CONTROL_HIGH) | + (1 << HPNA_NOISE) | + (1 << HPNA_NOISE_FLOOR) | + (1 << HPNA_NOISE_CEILING) | + (1 << HPNA_NOISE_ATTACK)); + + Offset = 2 /* Length and type fields */ + 2 /* Analog ctrl */ + 6; /* Regs */ + ExtraData = (BlockLength - Offset); + + if ((BlockData + ExtraData) > (SRomEnd - 1)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + for (i = 0; i < ExtraData / sizeof(USHORT); ++i) + { + UCHAR RegAddress = SRomHmrRegAddress(*BlockData++); + UCHAR RegValue = *BlockData++; + + Adapter->HpnaRegister[RegAddress] = RegValue; + Adapter->HpnaInitBitmap |= 1 << RegAddress; + } + +#if DBG + INFO_VERB("Analog Ctrl %04lx\n", Adapter->AnalogControl); + + for (i = 0; i < RTL_NUMBER_OF(Adapter->HpnaRegister); ++i) + { + if (Adapter->HpnaInitBitmap & (1 << i)) + { + INFO_VERB("HR Reg %02x = %02x\n", i, Adapter->HpnaRegister[i]); + } + } + + if (ExtraData % sizeof(USHORT)) + { + INFO_VERB("HR Data = %02x\n", *BlockData); + } +#endif + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomParseExtendedBlock( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRomEnd, + _In_ PUCHAR BlockData, + _Out_ PULONG BlockSize) +{ + NDIS_STATUS Status; + ULONG Length, Type; + + PAGED_CODE(); + + if (BlockData > (SRomEnd - 2)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + Length = SRomGetExtendedBlockLength(*BlockData++); + Type = *BlockData++; + + *BlockSize = Length; + + switch (Type) + { + case SROM_BLOCK_TYPE_GPR: + Status = SRomDecodeBlockGpr(Adapter, SRomEnd, BlockData); + break; + case SROM_BLOCK_TYPE_MII_1: + case SROM_BLOCK_TYPE_MII_2: + Status = SRomDecodeBlockMii(Adapter, + SRomEnd, + BlockData, + (Type == SROM_BLOCK_TYPE_MII_1)); + break; + case SROM_BLOCK_TYPE_SIA: + Status = SRomDecodeBlockSia(Adapter, SRomEnd, BlockData); + break; + case SROM_BLOCK_TYPE_SYM: + Status = SRomDecodeBlockSym(Adapter, SRomEnd, BlockData); + break; + case SROM_BLOCK_TYPE_RESET: + Status = SRomDecodeBlockReset(Adapter, SRomEnd, BlockData); + break; + case SROM_BLOCK_TYPE_HOMERUN: + Status = SRomDecodeBlockHmr(Adapter, SRomEnd, BlockData, Length); + break; + + /* Skip over the unused or unknown blocks */ + default: + WARN("Unknown block type %u, length %u\n", Type, Length); + case SROM_BLOCK_TYPE_PHY_SHUTDOWN: + Status = NDIS_STATUS_SUCCESS; + break; + } + + return Status; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomParse21041Block( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRomEnd, + _In_ PUCHAR BlockData, + _Out_ PULONG BlockSize) +{ + PDC_MEDIA Media; + UCHAR BlockStart; + ULONG MediaCode; + BOOLEAN HasExtendedData; + + PAGED_CODE(); + + if (BlockData > (SRomEnd - 1)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + BlockStart = *BlockData++; + + HasExtendedData = SRomBlockHasExtendedData(BlockStart); + if (BlockData > (SRomEnd - (HasExtendedData ? 7 : 1))) + return NDIS_STATUS_BUFFER_OVERFLOW; + + *BlockSize = HasExtendedData ? 7 : 1; + + MediaCode = SRomGetMediaCode(BlockStart); + if (MediaCode > SROM_MEDIA_MAX) + { + WARN("Unknown media code %u\n", MediaCode); + return NDIS_STATUS_SUCCESS; + } + Adapter->MediaBitmap |= 1 << MediaCode; + + Media = &Adapter->Media[MediaCode]; + + if (HasExtendedData) + { + Media->Csr13 = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Media->Csr14 = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + + Media->Csr15 = DcRetrieveWord(BlockData); + BlockData += sizeof(USHORT); + } + + INFO("SIA #%u %s, %sCSR13 %04lx CSR14 %04lx CSR15 %04lx\n", + MediaCode, + MediaNumber2Str(Adapter, MediaCode), + HasExtendedData ? "EXT " : "", + Media->Csr13, + Media->Csr14, + Media->Csr15); + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +BOOLEAN +SRomChecksumValid( + _In_ PUCHAR SRom) +{ + USHORT Checksum; + + PAGED_CODE(); + + Checksum = ~DcEthernetCrc(SRom, SROM_CHECKSUM_V1); + if (Checksum == DcRetrieveWord(&SRom[SROM_CHECKSUM_V1])) + return TRUE; + + Checksum = ~DcEthernetCrc(SRom, SROM_CHECKSUM_V2); + if (Checksum == DcRetrieveWord(&SRom[SROM_CHECKSUM_V2])) + return TRUE; + + return FALSE; +} + +static +CODE_SEG("PAGE") +BOOLEAN +AddressRomChecksumValid( + _In_reads_bytes_(EAR_SIZE) PVOID AddressRom) +{ + const UCHAR* Octet = AddressRom; + ULONG64 TestPatterm; + ULONG Checksum, i; + + NdisMoveMemory(&TestPatterm, &Octet[24], 8); + if (TestPatterm != EAR_TEST_PATTERN) + return FALSE; + + for (i = 0; i < 8; ++i) + { + if (Octet[i] != Octet[15 - i]) + return FALSE; + } + + Checksum = (Octet[0] << 10) + (Octet[2] << 9) + (Octet[4] << 8) + + (Octet[1] << 2) + (Octet[3] << 1) + Octet[5]; + Checksum %= 0xFFFF; + + return ((USHORT)Checksum == ((Octet[6] << 8) | Octet[7])); +} + +static +CODE_SEG("PAGE") +BOOLEAN +SRomReadMacAddress( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRom, + _Out_opt_ PULONG AddressOffset) +{ + ULONG MacOffset; + + /* Check if we have a board with an old EAR format */ + if (NdisEqualMemory(SRom, &SRom[16], 8)) + { + /* Validate the EAR checksum */ + if (!AddressRomChecksumValid(SRom)) + { + ERR("EAR has an invalid checksum\n"); + return FALSE; + } + + MacOffset = 0; + goto ReadMac; + } + + /* Check for a new SROM format */ + if (Adapter->ChipType != DC21040) + { + /* Validate the SROM checksum */ + if (SRomChecksumValid(SRom)) + { + MacOffset = SROM_MAC_ADDRESS; + goto ReadMac; + } + } + + /* Sanity check */ + if (*(PULONG)SRom == 0xFFFFFFF || *(PULONG)SRom == 0) + return FALSE; + + WARN("Legacy/unknown board found\n"); + MacOffset = 0; + +ReadMac: + if (AddressOffset) + *AddressOffset = MacOffset; + + NdisMoveMemory(Adapter->PermanentMacAddress, + &SRom[MacOffset], + ETH_LENGTH_OF_ADDRESS); + + return TRUE; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomParseHeader( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRom, + _Out_ PUCHAR* InfoLeaf, + _Out_ PUCHAR* SRomEnd) +{ + ULONG i, MacOffset, LeafOffset; + + PAGED_CODE(); + + if (!SRomReadMacAddress(Adapter, SRom, &MacOffset)) + { + ERR("Unable to read the MAC address\n"); + return NDIS_STATUS_FAILURE; + } + + /* Assign our own fake info leaf */ + if (MacOffset != SROM_MAC_ADDRESS) + { + for (i = 0; SRompRepairData[i].InfoLeaf; ++i) + { + /* Check for a MAC match */ + if (NdisEqualMemory(SRompRepairData[i].InfoLeaf, &Adapter->PermanentMacAddress, 3)) + { + /* This check is used to distinguish Accton EN1207 from Maxtech */ + if ((Adapter->PermanentMacAddress[0] == 0xE8) && (SRom[0x1A] == 0x55)) + ++i; + + break; + } + } + if (!SRompRepairData[i].InfoLeaf) + { + ERR("Non-standard SROM format, OUI %02x:%02x:%02x\n", + Adapter->PermanentMacAddress[0], + Adapter->PermanentMacAddress[1], + Adapter->PermanentMacAddress[2]); + + return NDIS_STATUS_ADAPTER_NOT_FOUND; + } + + *InfoLeaf = &SRompRepairData[i].InfoLeaf[3]; + *SRomEnd = *InfoLeaf + SRompRepairData[i].Length; + + /* Update the base address on multiport boards */ + Adapter->PermanentMacAddress[5] += Adapter->ControllerIndex; + +#if DBG + WARN("Non-standard SROM format, using '%s' info leaf\n", SRompRepairData[i].Name); +#endif + return STATUS_SUCCESS; + } + + /* Check if the SROM chip is shared between multiple controllers on a multiport board */ + if (SRom[SROM_CONTROLLER_COUNT] > 1) + { + INFO("Multiport board, controller number %u (%u/%u)\n", + Adapter->DeviceNumber, + Adapter->ControllerIndex + 1, + SRom[SROM_CONTROLLER_COUNT]); + + for (i = 0; i < SRom[SROM_CONTROLLER_COUNT]; ++i) + { + if (SROM_DEVICE_NUMBER(i) >= EE_SIZE) + return NDIS_STATUS_BUFFER_OVERFLOW; + + if (SRom[SROM_DEVICE_NUMBER(i)] == Adapter->DeviceNumber) + break; + } + if (i == SRom[SROM_CONTROLLER_COUNT]) + { + ERR("Controller %u was not found in the SROM\n", Adapter->DeviceNumber); + return NDIS_STATUS_ADAPTER_NOT_FOUND; + } + + if (SROM_LEAF_OFFSET(i) >= EE_SIZE) + return NDIS_STATUS_BUFFER_OVERFLOW; + + /* Update the base address */ + Adapter->PermanentMacAddress[5] += i; + } + else + { + i = 0; + } + + /* Controller info block offset */ + LeafOffset = DcRetrieveWord(SRom + SROM_LEAF_OFFSET(i)); + if (LeafOffset > (EE_SIZE - sizeof(DC_SROM_COMPACT_BLOCK))) + return NDIS_STATUS_BUFFER_OVERFLOW; + + /* Controller info leaf */ + *InfoLeaf = &SRom[LeafOffset]; + + *SRomEnd = SRom + EE_SIZE; + + return STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomParse( + _In_ PDC21X4_ADAPTER Adapter, + _In_ PUCHAR SRom) +{ + ULONG Index, BlockCount, BlockSize, DefaultMedia; + NDIS_STATUS Status; + USHORT GpioCtrl; + PUCHAR Data, SRomEnd; + + PAGED_CODE(); + + INFO("SROM Version %u, Controller count %u\n", + SRom[SROM_VERSION], + SRom[SROM_CONTROLLER_COUNT]); + + Status = SRomParseHeader(Adapter, SRom, &Data, &SRomEnd); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + DefaultMedia = DcRetrieveWord(Data); + Data += sizeof(USHORT); + + INFO("Default Media: %04lx\n", DefaultMedia); + + /* Direction of the GPIO pins */ + if (Adapter->ChipType == DC21140) + { + GpioCtrl = *Data++; + + INFO("GPIO Direction: %04lx\n", GpioCtrl); + + GpioCtrl |= DC_GPIO_CONTROL; + + for (Index = 0; Index < MEDIA_LIST_MAX; ++Index) + { + Adapter->Media[Index].GpioCtrl = GpioCtrl; + } + + /* Control word for block type 1 */ + Adapter->MiiMedia.SetupStream[0] = GpioCtrl; + } + + BlockCount = *Data++; + + INFO("Block Count: %u\n", BlockCount); + + if (BlockCount == 0 || BlockCount == 0xFF) + { + WARN("No media information found\n"); + return NDIS_STATUS_SUCCESS; + } + + /* Analyze and decode blocks */ + for (Index = 0; Index < BlockCount; ++Index) + { + if (Adapter->ChipType == DC21041) + { + Status = SRomParse21041Block(Adapter, SRomEnd, Data, &BlockSize); + } + else + { + if (Data > (SRomEnd - 1)) + return NDIS_STATUS_BUFFER_OVERFLOW; + + if (SRomIsBlockExtended(*Data)) + { + Status = SRomParseExtendedBlock(Adapter, SRomEnd, Data, &BlockSize); + } + else + { + Status = SRomDecodeBlockGpr(Adapter, SRomEnd, Data); + BlockSize = 4; + } + } + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + Data += BlockSize; + } + + if ((Adapter->MediaBitmap == 0) && !(Adapter->Features & DC_HAS_MII)) + { + WARN("No media information found\n"); + } + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +VOID +SRomShiftOut( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG Sequence, + _In_ ULONG BitCount) +{ + LONG i; + + PAGED_CODE(); + + for (i = BitCount - 1; i >= 0; --i) + { + ULONG DataIn = ((Sequence >> i) & 1) << DC_SERIAL_EE_DI_SHIFT; + + SROM_WRITE(Adapter, DataIn | DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS); + SROM_WRITE(Adapter, DataIn | DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS | + DC_SERIAL_EE_SK); + SROM_WRITE(Adapter, DataIn | DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS); + } +} + +static +CODE_SEG("PAGE") +USHORT +SRomShiftIn( + _In_ PDC21X4_ADAPTER Adapter) +{ + ULONG i, Csr; + USHORT SerialData; + + PAGED_CODE(); + + /* Shift the data out of the EEPROM */ + SerialData = 0; + for (i = 0; i < RTL_BITS_OF(USHORT); ++i) + { + SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS | DC_SERIAL_EE_SK); + + SROM_READ(Adapter, &Csr); + SerialData = (SerialData << 1) | ((Csr >> DC_SERIAL_EE_DO_SHIFT) & 1); + + SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS); + } + + /* End the read cycle */ + SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR); + + return SerialData; +} + +static +CODE_SEG("PAGE") +ULONG +SRomDetectAddressBusWidth( + _In_ PDC21X4_ADAPTER Adapter) +{ + ULONG Csr, BusWidth; + + PAGED_CODE(); + + /* Assume the SROM is a 1kB ROM, send the read command and zero address (6 bits) */ + SRomShiftOut(Adapter, EEPROM_CMD_READ << 6, EEPROM_CMD_LENGTH + 6); + + /* Check the preceding dummy zero bit */ + Csr = DC_READ(Adapter, DcCsr9_SerialInterface); + if (Csr & DC_SERIAL_EE_DO) + { + /* 4kB EEPROM */ + BusWidth = 8; + + /* Send the remaining part of the address */ + SRomShiftOut(Adapter, 0, 8 - 6); + + /* The preceding dummy bit must be zero */ + Csr = DC_READ(Adapter, DcCsr9_SerialInterface); + if (Csr & DC_SERIAL_EE_DO) + return 0; + } + else + { + /* 1kB EEPROM */ + BusWidth = 6; + } + + /* Complete the read cycle */ + (VOID)SRomShiftIn(Adapter); + + return BusWidth; +} + +static +CODE_SEG("PAGE") +BOOLEAN +SRomReadSRom( + _In_ PDC21X4_ADAPTER Adapter, + _Out_writes_all_(EE_SIZE) PVOID SRom) +{ + PUSHORT SRomWord = SRom; + BOOLEAN Success = TRUE; + ULONG BusWidth, Address; + + PAGED_CODE(); + + /* Select the device */ + SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR); + SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS); + + BusWidth = SRomDetectAddressBusWidth(Adapter); + if (BusWidth == 0) + { + Success = FALSE; + goto Done; + } + INFO("SROM Bus width: %u\n", BusWidth); + + /* Read the SROM contents once */ + for (Address = 0; Address < (EE_SIZE / sizeof(USHORT)); ++Address) + { + /* Send the command and address */ + SRomShiftOut(Adapter, + (EEPROM_CMD_READ << BusWidth) | Address, + EEPROM_CMD_LENGTH + BusWidth); + + /* Read the data */ + SRomWord[Address] = SRomShiftIn(Adapter); + } + +Done: + /* End chip select */ + DC_WRITE(Adapter, DcCsr9_SerialInterface, 0); + + return Success; +} + +#if DBG +static +CODE_SEG("PAGE") +VOID +SRomDumpContents( + _In_reads_bytes_(Length) const VOID* Buffer, + _In_ ULONG Length) +{ + ULONG Offset, Count, i; + const UCHAR* Data = Buffer; + + PAGED_CODE(); + + DbgPrint("SROM data:\n"); + + Offset = 0; + while (Offset < Length) + { + DbgPrint("%04x:\t", Offset); + + Count = min(Length - Offset, 16); + for (i = 0; i < Count; ++i, ++Offset) + { + DbgPrint("0x%02x, ", Data[Offset], (i == 7) ? '-' : ' '); + } + + DbgPrint("\n"); + } +} +#endif // DBG + +static +CODE_SEG("PAGE") +NDIS_STATUS +SRomRead( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_SROM_ENTRY SRomEntry; + NDIS_STATUS Status; + BOOLEAN ReleaseImage; + + PAGED_CODE(); + + Status = NdisAllocateMemoryWithTag((PVOID*)&SRomEntry, + FIELD_OFFSET(DC_SROM_ENTRY, SRomImage[EE_SIZE]), + DC21X4_TAG); + if (Status != NDIS_STATUS_SUCCESS) + return NDIS_STATUS_RESOURCES; + NdisZeroMemory(SRomEntry, FIELD_OFFSET(DC_SROM_ENTRY, SRomImage)); + + ReleaseImage = FALSE; + + if (SRomReadSRom(Adapter, SRomEntry->SRomImage)) + { + if (!SRomRegisterMasterAdapter(Adapter, SRomEntry)) + ReleaseImage = TRUE; + } + else + { + NdisFreeMemory(SRomEntry, 0, 0); + + if (!SRomFindMasterAdapter(Adapter, &SRomEntry)) + { + ERR("Failed to retrieve the SROM contents\n"); + return NDIS_STATUS_FAILURE; + } + } + + Status = SRomParse(Adapter, SRomEntry->SRomImage); + if (Status != NDIS_STATUS_SUCCESS) + { + ERR("Failed to parse SROM\n"); + } + +#if DBG + if (Status != NDIS_STATUS_SUCCESS) + SRomDumpContents(SRomEntry->SRomImage, EE_SIZE); +#endif + + if (ReleaseImage) + NdisFreeMemory(SRomEntry, 0, 0); + + return Status; +} + +static +CODE_SEG("PAGE") +BOOLEAN +AddressRomReadData( + _In_ PDC21X4_ADAPTER Adapter, + _Out_writes_all_(EAR_SIZE) PUCHAR AddressRom) +{ + ULONG Data, i, j; + + PAGED_CODE(); + + /* Reset the ROM pointer */ + DC_WRITE(Adapter, DcCsr9_SerialInterface, 0); + + for (i = 0; i < EAR_SIZE; ++i) + { + for (j = 10000; j > 0; --j) + { + NdisStallExecution(1); + Data = DC_READ(Adapter, DcCsr9_SerialInterface); + + if (!(Data & DC_SERIAL_EAR_DN)) + break; + } + AddressRom[i] = Data & DC_SERIAL_EAR_DT; + } + + if (SRomIsEmpty(AddressRom, EAR_SIZE)) + return FALSE; + + return TRUE; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +AddressRomRead( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_SROM_ENTRY SRomEntry; + NDIS_STATUS Status; + BOOLEAN ReleaseImage; + + PAGED_CODE(); + + Status = NdisAllocateMemoryWithTag((PVOID*)&SRomEntry, + FIELD_OFFSET(DC_SROM_ENTRY, SRomImage[EAR_SIZE]), + DC21X4_TAG); + if (Status != NDIS_STATUS_SUCCESS) + return NDIS_STATUS_RESOURCES; + NdisZeroMemory(SRomEntry, FIELD_OFFSET(DC_SROM_ENTRY, SRomImage)); + + ReleaseImage = FALSE; + + if (AddressRomReadData(Adapter, SRomEntry->SRomImage)) + { + if (!SRomRegisterMasterAdapter(Adapter, SRomEntry)) + ReleaseImage = TRUE; + } + else + { + NdisFreeMemory(SRomEntry, 0, 0); + + if (!SRomFindMasterAdapter(Adapter, &SRomEntry)) + { + ERR("Failed to retrieve the EAR contents\n"); + return NDIS_STATUS_FAILURE; + } + } + + if (!SRomReadMacAddress(Adapter, SRomEntry->SRomImage, NULL)) + { + ERR("Unable to read the MAC address\n"); + Status = NDIS_STATUS_FAILURE; + } + + /* Update the base address on multiport boards */ + Adapter->PermanentMacAddress[5] += Adapter->ControllerIndex; + +#if DBG + if (Status != NDIS_STATUS_SUCCESS) + SRomDumpContents(SRomEntry->SRomImage, EAR_SIZE); +#endif + + if (ReleaseImage) + NdisFreeMemory(SRomEntry, 0, 0); + + return Status; +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +CODE_SEG("PAGE") +VOID +DcFreeEeprom( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_SROM_ENTRY SRomEntry; + + PAGED_CODE(); + + SRomEntry = Adapter->SRomEntry; + if (!SRomEntry) + return; + + SRomAcquireListMutex(); + + /* Unregister the port */ + SRomEntry->DeviceBitmap &= ~(1 << Adapter->DeviceNumber); + + /* + * Free the SROM as soon as the last registered port has removed. + * We can't free it in an unload handler + * as the bus numbers can be changed by a resource rebalance. + */ + if (SRomEntry->DeviceBitmap == 0) + { + INFO("Freeing SROM %p at %u:%u\n", + SRomEntry, + SRomEntry->BusNumber, + SRomEntry->DeviceNumber); + + RemoveEntryList(&SRomEntry->ListEntry); + + NdisFreeMemory(SRomEntry, 0, 0); + } + + SRomReleaseListMutex(); +} + +CODE_SEG("PAGE") +NDIS_STATUS +DcReadEeprom( + _In_ PDC21X4_ADAPTER Adapter) +{ + NDIS_STATUS Status; + + PAGED_CODE(); + + if (Adapter->ChipType == DC21040) + { + /* Ethernet Address ROM */ + Status = AddressRomRead(Adapter); + } + else + { + /* MicroWire Compatible Serial EEPROM */ + Status = SRomRead(Adapter); + } + + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + INFO("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]); + + if (ETH_IS_BROADCAST(Adapter->PermanentMacAddress) || + ETH_IS_EMPTY(Adapter->PermanentMacAddress) || + ETH_IS_MULTICAST(Adapter->PermanentMacAddress)) + { + ERR("Invalid permanent MAC address %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]); + + NdisWriteErrorLogEntry(Adapter->AdapterHandle, NDIS_ERROR_CODE_NETWORK_ADDRESS, 0); + + return NDIS_STATUS_INVALID_ADDRESS; + } + + return NDIS_STATUS_SUCCESS; +} diff --git a/drivers/network/dd/dc21x4/eeprom.h b/drivers/network/dd/dc21x4/eeprom.h new file mode 100644 index 00000000000..58d44202def --- /dev/null +++ b/drivers/network/dd/dc21x4/eeprom.h @@ -0,0 +1,108 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: EEPROM specific definitions + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +#pragma once + +#include <pshpack1.h> +typedef struct _DC_SROM_COMPACT_BLOCK +{ + USHORT SelectedConnectionType; + UCHAR GpioDirection; /* 21140 only */ + UCHAR BlockCount; +} DC_SROM_COMPACT_BLOCK, *PDC_SROM_COMPACT_BLOCK; +#include <poppack.h> + +typedef struct _DC_SROM_REPAIR_ENTRY +{ +#if DBG + PCSTR Name; +#endif + PUCHAR InfoLeaf; + ULONG Length; +} DC_SROM_REPAIR_ENTRY, *PDC_SROM_REPAIR_ENTRY; + +typedef struct _DC_SROM_ENTRY +{ + LIST_ENTRY ListEntry; + ULONG BusNumber; + DC_CHIP_TYPE ChipType; + UCHAR DeviceNumber; + ULONG InterruptLevel; + ULONG InterruptVector; + ULONG DeviceBitmap; + UCHAR SRomImage[ANYSIZE_ARRAY]; +} DC_SROM_ENTRY, *PDC_SROM_ENTRY; + +#define SRomIsBlockExtended(Byte) ((Byte) & 0x80) +#define SRomGetExtendedBlockLength(Byte) (((Byte) & 0x7F) + 1) +#define SRomGetMediaCode(Byte) ((Byte) & 0x3F) +#define SRomBlockHasExtendedData(Byte) ((Byte) & 0x40) +#define SRomIsDefaultMedia(Word) ((Word) & 0x4000) +#define SRomMediaHasActivityIndicator(Word) (((Word) & 0x8000) == 0) +#define SRomMediaActivityIsActiveLow(Word) ((Word) & 0x80) +#define SRomMediaGetSenseMask(Word) (1 << (((Word) & 0x0E) >> 1)) +#define SRomCommandToOpMode(Word) (((Word) & 0x71) << 18) +#define SRomMediaAutoSense(Media) ((Media) & 0x800) +#define SRomMediaToMediaNumber(Word) ((Word) & 0x1F) +#define SRomHmrRegAddress(Byte) ((Byte) & 0x1F) + +#define SROM_OPMODE_MASK \ + (DC_OPMODE_PORT_SELECT | \ + DC_OPMODE_PORT_XMIT_10 | \ + DC_OPMODE_PORT_PCS | \ + DC_OPMODE_PORT_SCRAMBLER) + +#define EE_SIZE 128 +#define EAR_SIZE 32 + +#define EAR_TEST_PATTERN 0xAA5500FFAA5500FFULL + +#define EEPROM_CMD_WRITE 5 +#define EEPROM_CMD_READ 6 +#define EEPROM_CMD_ERASE 7 + +#define EEPROM_CMD_LENGTH 3 + +/* + * Various offsets in the SROM + */ +#define SROM_VERSION 18 +#define SROM_CONTROLLER_COUNT 19 +#define SROM_MAC_ADDRESS 20 +#define SROM_DEVICE_NUMBER(n) (26 + ((n) * 3)) +#define SROM_LEAF_OFFSET(n) (27 + ((n) * 3)) +#define SROM_CHECKSUM_V1 126 +#define SROM_CHECKSUM_V2 94 + +/* + * SROM compact and extended format types + */ +#define SROM_BLOCK_TYPE_GPR 0 +#define SROM_BLOCK_TYPE_MII_1 1 +#define SROM_BLOCK_TYPE_SIA 2 +#define SROM_BLOCK_TYPE_MII_2 3 +#define SROM_BLOCK_TYPE_SYM 4 +#define SROM_BLOCK_TYPE_RESET 5 +#define SROM_BLOCK_TYPE_PHY_SHUTDOWN 6 +#define SROM_BLOCK_TYPE_HOMERUN 7 + +#define SROM_MAX_STREAM_REGS 6 + +/* + * SROM media codes + */ +#define SROM_MEDIA_10T 0 +#define SROM_MEDIA_BNC 1 +#define SROM_MEDIA_AUI 2 +#define SROM_MEDIA_100T_HD 3 +#define SROM_MEDIA_10T_FD 4 +#define SROM_MEDIA_100TX_FD 5 +#define SROM_MEDIA_100T4 6 +#define SROM_MEDIA_100FX_HD 7 +#define SROM_MEDIA_100FX_FD 8 +#define SROM_MEDIA_MAX 8 +#define SROM_MEDIA_HMR 18 diff --git a/drivers/network/dd/dc21x4/eeprom_data.c b/drivers/network/dd/dc21x4/eeprom_data.c new file mode 100644 index 00000000000..f00f80b293d --- /dev/null +++ b/drivers/network/dd/dc21x4/eeprom_data.c @@ -0,0 +1,219 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: EEPROM data for boards without the standard SROM Format + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +/* Adapted from the Linux tulip driver written by Donald Becker */ + +/* INCLUDES *******************************************************************/ + +#include "dc21x4.h" + +/* GLOBALS ********************************************************************/ + +/* Asante */ +static DC_PG_DATA UCHAR SRompLeafAsante[] = +{ + 0x00, 0x00, 0x94, + + 0x00, 0x08, // Default Autoselect + 0x00, // GPIO direction + 0x01, // 1 block + + 0x80 + 12, // Extended block, 12 bytes + 0x01, // MII + 0x00, // PHY #0 + 0x00, // GPIO stream length + 0x00, // Reset stream length + 0x00, 0x78, // Capabilities + 0xE0, 0x01, // Advertisement + 0x00, 0x50, // FDX + 0x00, 0x18, // TTM +}; + +/* SMC 9332DST */ +static DC_PG_DATA UCHAR SRompLeaf9332[] = +{ + 0x00, 0x00, 0xC0, + + 0x00, 0x08, // Default Autoselect + 0x1F, // GPIO direction + 0x04, // 4 blocks + + 0x00, // GPR 0 + 0x00, // GPIO data + 0x9E, 0x00, // Command 0x009E + + 0x04, // GPR 4 + 0x00, // GPIO data + 0x9E, 0x00, // Command 0x009E + 0x03, // GPR 3 + 0x09, // GPIO data + 0x6D, 0x00, // Command 0x006D + + 0x05, // GPR 5 + 0x09, // GPIO data + 0x6D, 0x00, // Command 0x006D +}; + +/* Cogent EM100 */ +static DC_PG_DATA UCHAR SRompLeafEm100[] = +{ + 0x00, 0x00, 0x92, + + 0x00, 0x08, // Default Autoselect + 0x3F, // GPIO direction + 0x06, // 6 blocks + + 0x07, // GPR 7 + 0x01, // GPIO data + 0x21, 0x80, // Command 0x8021 + + 0x08, // GPR 8 + 0x01, // GPIO data + 0x21, 0x80, // Command 0x8021 + + 0x00, // GPR 0 + 0x01, // GPIO data + 0x9E, 0x00, // Command 0x009E + + 0x04, // GPR 4 + 0x01, // GPIO data + 0x9E, 0x00, // Command 0x009E + + 0x03, // GPR 3 + 0x01, // GPIO data + 0x6D, 0x00, // Command 0x006D + + 0x05, // GPR 5 + 0x01, // GPIO data + 0x6D, 0x00, // Command 0x006D +}; + +/* Maxtech NX-110 */ +static DC_PG_DATA UCHAR SRompLeafNx110[] = +{ + 0x00, 0x00, 0xE8, + + 0x00, 0x08, // Default Autoselect + 0x13, // GPIO direction + 0x05, // 5 blocks + + 0x01, // GPR 1 + 0x10, // GPIO data + 0x9E, 0x00, // Command 0x009E + + 0x00, // GPR 0 + 0x00, // GPIO data + 0x9E, 0x00, // Command 0x009E + + 0x04, // GPR 4 + 0x00, // GPIO data + 0x9E, 0x00, // Command 0x009E + + 0x03, // GPR 3 + 0x03, // GPIO data + 0x6D, 0x00, // Command 0x006D + + 0x05, // GPR 5 + 0x03, // GPIO data + 0x6D, 0x00, // Command 0x006D +}; + +/* Accton EN1207 */ +static DC_PG_DATA UCHAR SRompLeafEn1207[] = +{ + 0x00, 0x00, 0xE8, + + 0x00, 0x08, // Default Autoselect + 0x1F, // GPIO direction + 0x05, // 5 blocks + + 0x01, // GPR 1 + 0x1B, // GPIO data + 0x00, 0x00, // Command 0x0000 + + 0x00, // GPR 0 + 0x0B, // GPIO data + 0x9E, 0x00, // Command 0x009E + + 0x04, // GPR 4 + 0x0B, // GPIO data + 0x9E, 0x00, // Command 0x009E + + 0x03, // GPR 3 + 0x1B, // GPIO data + 0x6D, 0x00, // Command 0x006D + + 0x05, // GPR 5 + 0x1B, // GPIO data + 0x6D, 0x00, // Command 0x006D +}; + +/* NetWinder */ +static DC_PG_DATA UCHAR SRompLeafNetWinder[] = +{ + 0x00, 0x10, 0x57, + + 0x00, 0x08, // Default Autoselect + 0x01, // 1 block + + 0x80 + 21, // Extended block, 21 bytes + 0x03, // MII + 0x01, // PHY #1 + 0x00, // GPIO stream length + 0x03, // Reset stream length + 0x21, 0x08, + 0x00, 0x00, + 0x01, 0x00, + 0x00, 0x00, // Capabilities + 0xE1, 0x01, // Advertisement + 0x00, 0x00, // FDX + 0x00, 0x00, // TTM + 0x00, // PHY cannot be unplugged +}; + +/* Cobalt Microserver */ +static DC_PG_DATA UCHAR SRompLeafCobaltMicroserver[] = +{ + 0x00, 0x10, 0xE0, + + 0x00, 0x08, // Default Autoselect + 0x01, // 1 block + + 0x80 + 21, // Extended block, 21 bytes + 0x03, // MII + 0x00, // PHY #0 + 0x00, // GPIO stream length + 0x04, // Reset stream length + 0x01, 0x08, // Set control mode, GP0 output + 0x00, 0x00, // Drive GP0 Low (RST is active low) + 0x00, 0x08, // Control mode, GP0 input (undriven) + 0x00, 0x00, // Clear control mode + 0x00, 0x78, // Capabilities: 100TX FDX + HDX, 10bT FDX + HDX + 0xE0, 0x01, // Advertise all above + 0x00, 0x50, // FDX all above + 0x00, 0x18, // Set fast TTM in 100bt modes + 0x00, // PHY cannot be unplugged +}; + +#if DBG +#define DEFINE_BOARD(Leaf, Name) { Name, Leaf, sizeof(Leaf) - 3 /* OUI (3 bytes) */} +#else +#define DEFINE_BOARD(Leaf, Name) { Leaf, sizeof(Leaf) - 3 } +#endif + +DC_PG_DATA +DC_SROM_REPAIR_ENTRY SRompRepairData[] = +{ + DEFINE_BOARD(SRompLeafAsante, "Asante"), + DEFINE_BOARD(SRompLeaf9332, "SMC 9332DST"), + DEFINE_BOARD(SRompLeafEm100, "Cogent EM100"), + DEFINE_BOARD(SRompLeafNx110, "Maxtech NX-110"), + DEFINE_BOARD(SRompLeafEn1207, "Accton EN1207"), // Must be defined after the NX-110 + DEFINE_BOARD(SRompLeafNetWinder, "NetWinder"), + DEFINE_BOARD(SRompLeafCobaltMicroserver, "Cobalt Microserver"), + DEFINE_BOARD(NULL, NULL), +}; diff --git a/drivers/network/dd/dc21x4/hardware.c b/drivers/network/dd/dc21x4/hardware.c new file mode 100644 index 00000000000..971c10d6d1a --- /dev/null +++ b/drivers/network/dd/dc21x4/hardware.c @@ -0,0 +1,585 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Hardware specific functions + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +/* INCLUDES *******************************************************************/ + +#include "dc21x4.h" + +#include <debug.h> + +/* FUNCTIONS ******************************************************************/ + +VOID +DcDisableHw( + _In_ PDC21X4_ADAPTER Adapter) +{ + ULONG OpMode; + + /* Disable interrupts */ + DC_WRITE(Adapter, DcCsr7_IrqMask, 0); + + /* Stop DMA */ + OpMode = Adapter->OpMode; + OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE); + DC_WRITE(Adapter, DcCsr6_OpMode, OpMode); + + /* Put the adapter to snooze mode */ + DcPowerSave(Adapter, TRUE); + + /* Perform a software reset */ + DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET); +} + +VOID +DcStopTxRxProcess( + _In_ PDC21X4_ADAPTER Adapter) +{ + ULONG i, OpMode, Status; + + OpMode = Adapter->OpMode; + OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE); + DC_WRITE(Adapter, DcCsr6_OpMode, OpMode); + + for (i = 0; i < 5000; ++i) + { + Status = DC_READ(Adapter, DcCsr5_Status); + + if (((Status & DC_STATUS_TX_STATE_MASK) == DC_STATUS_TX_STATE_STOPPED) && + ((Status & DC_STATUS_RX_STATE_MASK) == DC_STATUS_RX_STATE_STOPPED)) + { + return; + } + + NdisStallExecution(10); + } + + WARN("Failed to stop the TX/RX process 0x%08lx\n", Status); +} + +VOID +DcWriteGpio( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG Value) +{ + ULONG Data, Register; + + /* Some chips don't have a separate GPIO register */ + if (Adapter->Features & DC_SIA_GPIO) + { + Data = Adapter->SiaSetting; + Data &= 0x0000FFFF; /* SIA */ + Data |= Value << 16; /* GPIO */ + Adapter->SiaSetting = Data; + + Register = DcCsr15_SiaGeneral; + } + else + { + Data = Value; + Register = DcCsr12_Gpio; + } + DC_WRITE(Adapter, Register, Data); +} + +VOID +DcWriteSia( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG Csr13, + _In_ ULONG Csr14, + _In_ ULONG Csr15) +{ + ULONG SiaConn, SiaGen; + + TRACE("CSR13 %08lx, CSR14 %08lx, CSR15 %08lx\n", Csr13, Csr14, Csr15); + + SiaConn = 0; + + /* The 21145 comes with 16 new bits in CSR13 */ + if (Adapter->Features & DC_SIA_ANALOG_CONTROL) + { + SiaConn = Adapter->AnalogControl; + } + + /* Reset the transceiver */ + DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | DC_SIA_CONN_RESET); + NdisStallExecution(20); + + /* Some chips don't have a separate GPIO register */ + if (Adapter->Features & DC_SIA_GPIO) + { + SiaGen = Adapter->SiaSetting; + SiaGen &= 0xFFFF0000; /* GPIO */ + SiaGen |= Csr15; /* SIA */ + Adapter->SiaSetting = SiaGen; + } + else + { + SiaGen = Csr15; + } + + DC_WRITE(Adapter, DcCsr14_SiaTxRx, Csr14); + DC_WRITE(Adapter, DcCsr15_SiaGeneral, SiaGen); + + /* Don't reset the transceiver twice */ + if (Csr13 == DC_SIA_CONN_RESET) + return; + + DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | Csr13); +} + +VOID +DcTestPacket( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_TCB Tcb; + PDC_TBD Tbd; + ULONG FrameNumber; + + Adapter->MediaTestStatus = FALSE; + Adapter->ModeFlags |= DC_MODE_TEST_PACKET; + + if (!Adapter->LoopbackFrameSlots) + { + ERR("Failed to complete test packets, CSR12 %08lx, CSR5 %08lx\n", + DC_READ(Adapter, DcCsr12_SiaStatus), + DC_READ(Adapter, DcCsr5_Status)); + + /* Try to recover the lost TX buffers */ + NdisScheduleWorkItem(&Adapter->TxRecoveryWorkItem); + return; + } + + --Adapter->LoopbackFrameSlots; + + FrameNumber = (Adapter->LoopbackFrameNumber++) % DC_LOOPBACK_FRAMES; + + Tbd = Adapter->CurrentTbd; + Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd); + + Tcb = Adapter->CurrentTcb; + Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb); + + Tcb->Tbd = Tbd; + Tcb->Packet = NULL; + + ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED)); + + /* Put the loopback frame on the transmit ring */ + Tbd->Address1 = Adapter->LoopbackFramePhys[FrameNumber]; + Tbd->Address2 = 0; + Tbd->Control &= DC_TBD_CONTROL_END_OF_RING; + Tbd->Control |= DC_LOOPBACK_FRAME_SIZE | + DC_TBD_CONTROL_FIRST_FRAGMENT | + DC_TBD_CONTROL_LAST_FRAGMENT | + DC_TBD_CONTROL_REQUEST_INTERRUPT; + DC_WRITE_BARRIER(); + Tbd->Status = DC_TBD_STATUS_OWNED; + + /* Send the loopback packet to verify connectivity of a media */ + DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL); +} + +BOOLEAN +DcSetupFrameDownload( + _In_ PDC21X4_ADAPTER Adapter, + _In_ BOOLEAN WaitForCompletion) +{ + PDC_TCB Tcb; + PDC_TBD Tbd; + ULONG i, Control; + + Tbd = Adapter->CurrentTbd; + + /* Ensure correct setup frame processing */ + if (Tbd != Adapter->HeadTbd) + { + ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED)); + + /* Put the null frame on the transmit ring */ + Tbd->Control &= DC_TBD_CONTROL_END_OF_RING; + Tbd->Address1 = 0; + Tbd->Address2 = 0; + DC_WRITE_BARRIER(); + Tbd->Status = DC_TBD_STATUS_OWNED; + + Tbd = DC_NEXT_TBD(Adapter, Tbd); + } + + Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd); + + Tcb = Adapter->CurrentTcb; + Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb); + + Tcb->Tbd = Tbd; + Tcb->Packet = NULL; + + ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED)); + + /* Prepare the setup frame */ + Tbd->Address1 = Adapter->SetupFramePhys; + Tbd->Address2 = 0; + Tbd->Control &= DC_TBD_CONTROL_END_OF_RING; + Control = DC_SETUP_FRAME_SIZE | DC_TBD_CONTROL_SETUP_FRAME; + if (!WaitForCompletion) + Control |= DC_TBD_CONTROL_REQUEST_INTERRUPT; + if (Adapter->ProgramHashPerfectFilter) + Control |= DC_TBD_CONTROL_HASH_PERFECT_FILTER; + Tbd->Control |= Control; + DC_WRITE_BARRIER(); + Tbd->Status = DC_TBD_STATUS_OWNED; + + DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL); + + if (!WaitForCompletion) + return TRUE; + + /* Wait up to 500 ms for the chip to process the setup frame */ + for (i = 50000; i > 0; --i) + { + NdisStallExecution(10); + + KeMemoryBarrierWithoutFence(); + if (!(Tbd->Status & DC_TBD_STATUS_OWNED)) + break; + } + if (i == 0) + { + ERR("Failed to complete setup frame %08lx\n", Tbd->Status); + return FALSE; + } + + return TRUE; +} + +CODE_SEG("PAGE") +VOID +DcSetupFrameInitialize( + _In_ PDC21X4_ADAPTER Adapter) +{ + PULONG SetupFrame, SetupFrameStart; + PUSHORT MacAddress; + ULONG i; + + PAGED_CODE(); + + SetupFrame = Adapter->SetupFrame; + + /* Add the physical address entry */ + MacAddress = (PUSHORT)Adapter->CurrentMacAddress; + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]); + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]); + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]); + + /* Pad to 16 addresses */ + SetupFrameStart = Adapter->SetupFrame; + for (i = 1; i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES; ++i) + { + *SetupFrame++ = SetupFrameStart[0]; + *SetupFrame++ = SetupFrameStart[1]; + *SetupFrame++ = SetupFrameStart[2]; + } +} + +static +VOID +DcSetupFramePerfectFiltering( + _In_ PDC21X4_ADAPTER Adapter) +{ + PULONG SetupFrame, SetupFrameStart; + PUSHORT MacAddress; + ULONG i; + + SetupFrame = Adapter->SetupFrame; + + /* Add the physical address entry */ + MacAddress = (PUSHORT)Adapter->CurrentMacAddress; + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]); + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]); + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]); + + /* Store multicast addresses */ + for (i = 0; i < Adapter->MulticastCount; ++i) + { + MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress; + + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]); + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]); + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]); + } + + ++i; + + /* Add the broadcast address entry */ + if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST) + { + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF); + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF); + *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF); + + ++i; + } + + /* Pad to 16 addresses */ + SetupFrameStart = Adapter->SetupFrame; + while (i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES) + { + *SetupFrame++ = SetupFrameStart[0]; + *SetupFrame++ = SetupFrameStart[1]; + *SetupFrame++ = SetupFrameStart[2]; + + ++i; + } +} + +static +VOID +DcSetupFrameImperfectFiltering( + _In_ PDC21X4_ADAPTER Adapter) +{ + PULONG SetupFrame = Adapter->SetupFrame; + PUSHORT MacAddress; + ULONG Hash, i; + + RtlZeroMemory(SetupFrame, DC_SETUP_FRAME_SIZE); + + /* Fill up the 512-bit multicast hash table */ + for (i = 0; i < Adapter->MulticastCount; ++i) + { + MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress; + + /* Only need lower 9 bits of the hash */ + Hash = DcEthernetCrc(MacAddress, ETH_LENGTH_OF_ADDRESS); + Hash &= 512 - 1; + SetupFrame[Hash / 16] |= 1 << (Hash % 16); + } + + /* Insert the broadcast address hash to the bin */ + if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST) + { + Hash = DC_SETUP_FRAME_BROADCAST_HASH; + SetupFrame[Hash / 16] |= 1 << (Hash % 16); + } + + /* Add the physical address entry */ + MacAddress = (PUSHORT)Adapter->CurrentMacAddress; + SetupFrame[39] = DC_SETUP_FRAME_ENTRY(MacAddress[0]); + SetupFrame[40] = DC_SETUP_FRAME_ENTRY(MacAddress[1]); + SetupFrame[41] = DC_SETUP_FRAME_ENTRY(MacAddress[2]); +} + +NDIS_STATUS +DcUpdateMulticastList( + _In_ PDC21X4_ADAPTER Adapter) +{ + BOOLEAN UsePerfectFiltering; + + /* If more than 14 addresses are requested, switch to hash filtering mode */ + UsePerfectFiltering = (Adapter->MulticastCount <= DC_SETUP_FRAME_ADDRESSES); + + Adapter->ProgramHashPerfectFilter = UsePerfectFiltering; + Adapter->OidPending = TRUE; + + if (UsePerfectFiltering) + DcSetupFramePerfectFiltering(Adapter); + else + DcSetupFrameImperfectFiltering(Adapter); + + NdisAcquireSpinLock(&Adapter->SendLock); + + DcSetupFrameDownload(Adapter, FALSE); + + NdisReleaseSpinLock(&Adapter->SendLock); + + return NDIS_STATUS_PENDING; +} + +NDIS_STATUS +DcApplyPacketFilter( + _In_ PDC21X4_ADAPTER Adapter, + _In_ ULONG PacketFilter) +{ + ULONG OpMode, OldPacketFilter; + + INFO("Packet filter value 0x%lx\n", PacketFilter); + + NdisAcquireSpinLock(&Adapter->ModeLock); + + /* Update the filtering mode */ + OpMode = Adapter->OpMode; + OpMode &= ~(DC_OPMODE_RX_PROMISCUOUS | DC_OPMODE_RX_ALL_MULTICAST); + if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) + { + OpMode |= DC_OPMODE_RX_PROMISCUOUS; + } + else if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) + { + OpMode |= DC_OPMODE_RX_ALL_MULTICAST; + } + Adapter->OpMode = OpMode; + DC_WRITE(Adapter, DcCsr6_OpMode, OpMode); + + NdisReleaseSpinLock(&Adapter->ModeLock); + + OldPacketFilter = Adapter->PacketFilter; + Adapter->PacketFilter = PacketFilter; + + /* Program the NIC to receive or reject broadcast frames */ + if ((OldPacketFilter ^ PacketFilter) & NDIS_PACKET_TYPE_BROADCAST) + { + return DcUpdateMulticastList(Adapter); + } + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +VOID +DcSoftReset( + _In_ PDC21X4_ADAPTER Adapter) +{ + PAGED_CODE(); + + /* Linux driver does this */ + if (Adapter->Features & DC_HAS_MII) + { + /* Select the MII/SYM port */ + DC_WRITE(Adapter, DcCsr6_OpMode, DC_OPMODE_PORT_SELECT); + } + + /* Perform a software reset */ + DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET); + NdisMSleep(100); + DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode); +} + +CODE_SEG("PAGE") +NDIS_STATUS +DcSetupAdapter( + _In_ PDC21X4_ADAPTER Adapter) +{ + PAGED_CODE(); + + DcInitTxRing(Adapter); + DcInitRxRing(Adapter); + + /* Initial values */ + if (!MEDIA_IS_FIXED(Adapter)) + { + Adapter->LinkSpeedMbps = 10; + } + Adapter->MediaNumber = Adapter->DefaultMedia; + Adapter->ModeFlags &= ~(DC_MODE_PORT_AUTOSENSE | DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED | + DC_MODE_TEST_PACKET | DC_MODE_AUTONEG_MASK); + + DcSoftReset(Adapter); + + /* Receive descriptor ring buffer */ + DC_WRITE(Adapter, DcCsr3_RxRingAddress, Adapter->RbdPhys); + + /* Transmit descriptor ring buffer */ + DC_WRITE(Adapter, DcCsr4_TxRingAddress, Adapter->TbdPhys); + + switch (Adapter->ChipType) + { + case DC21040: + { + DcWriteSia(Adapter, + Adapter->Media[Adapter->MediaNumber].Csr13, + Adapter->Media[Adapter->MediaNumber].Csr14, + Adapter->Media[Adapter->MediaNumber].Csr15); + + /* Explicitly specifed by user */ + if (Adapter->MediaNumber == MEDIA_10T_FD) + { + Adapter->OpMode |= DC_OPMODE_FULL_DUPLEX; + } + break; + } + + case DC21041: + { + MediaSiaSelect(Adapter); + break; + } + + case DC21140: + { + if (Adapter->MediaNumber == MEDIA_MII) + { + MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP)); + MediaMiiSelect(Adapter); + } + else + { + /* All media use the same GPIO directon */ + DC_WRITE(Adapter, DcCsr12_Gpio, Adapter->Media[Adapter->MediaNumber].GpioCtrl); + NdisStallExecution(10); + + MediaGprSelect(Adapter); + } + break; + } + + case DC21143: + case DC21145: + { + /* Init the HPNA PHY */ + if ((Adapter->MediaBitmap & (1 << MEDIA_HMR)) && Adapter->HpnaInitBitmap) + { + HpnaPhyInit(Adapter); + } + + if (Adapter->MediaNumber == MEDIA_MII) + { + MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP)); + MediaMiiSelect(Adapter); + break; + } + + /* If the current media is FX, assume we have a link */ + if (MEDIA_IS_FX(Adapter->MediaNumber)) + { + Adapter->LinkUp = TRUE; + + NdisMIndicateStatus(Adapter->AdapterHandle, + NDIS_STATUS_MEDIA_CONNECT, + NULL, + 0); + NdisMIndicateStatusComplete(Adapter->AdapterHandle); + } + + MediaSiaSelect(Adapter); + break; + } + + default: + ASSERT(FALSE); + UNREACHABLE; + break; + } + + /* Start the TX process */ + Adapter->OpMode |= DC_OPMODE_TX_ENABLE; + DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode); + + /* Load the address recognition RAM */ + if (!DcSetupFrameDownload(Adapter, TRUE)) + { + /* This normally should not happen */ + ASSERT(FALSE); + + NdisWriteErrorLogEntry(Adapter->AdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 1, + __LINE__); + + return NDIS_STATUS_HARD_ERRORS; + } + + return NDIS_STATUS_SUCCESS; +} diff --git a/drivers/network/dd/dc21x4/init.c b/drivers/network/dd/dc21x4/init.c new file mode 100644 index 00000000000..1bcec4d9a65 --- /dev/null +++ b/drivers/network/dd/dc21x4/init.c @@ -0,0 +1,1321 @@ +/* + * PROJECT: ReactOS DC21x4 Driver + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Miniport initialization helper routines + * COPYRIGHT: Copyright 2023 Dmitry Borisov di.sean@protonmail.com + */ + +/* INCLUDES *******************************************************************/ + +#include "dc21x4.h" + +#include <debug.h> + +/* GLOBALS ********************************************************************/ + +/* + * The driver must align the buffers on a 4 byte boundary to meet the hardware requirement. + * We stick with cache alignment to get better performance. + */ +C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_RECEIVE_BUFFER_ALIGNMENT) == 0); +C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_DESCRIPTOR_ALIGNMENT) == 0); +C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_SETUP_FRAME_ALIGNMENT) == 0); + +/* Errata: The end of receive buffer must not fall on a cache boundary */ +#define DC_RECEIVE_BUFFER_SIZE (DC_RECEIVE_BLOCK_SIZE - 4) +C_ASSERT((DC_RECEIVE_BUFFER_SIZE % 32) != 0); + +#define DC_MEM_BLOCK_SIZE_RCB \ + (DC_RECEIVE_BLOCK_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1) + +#define DC_MEM_BLOCK_SIZE_RBD \ + (sizeof(DC_RBD) * DC_RECEIVE_BUFFERS_DEFAULT + SYSTEM_CACHE_ALIGNMENT_SIZE - 1) + +#define DC_MEM_BLOCK_SIZE_TBD_AUX \ + (sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS + SYSTEM_CACHE_ALIGNMENT_SIZE - 1 + \ + DC_SETUP_FRAME_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1 + \ + DC_LOOPBACK_FRAME_SIZE * DC_LOOPBACK_FRAMES + SYSTEM_CACHE_ALIGNMENT_SIZE - 1) + +#define DC_MEM_BLOCK_SIZE_TX_BUFFER \ + (DC_TRANSMIT_BLOCK_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1) + +/* FUNCTIONS ******************************************************************/ + +static +CODE_SEG("PAGE") +VOID +DcConfigQueryInteger( + _In_ NDIS_HANDLE ConfigurationHandle, + _In_ PCWSTR EntryName, + _Out_ PULONG EntryContext, + _In_ ULONG DefaultValue, + _In_ ULONG Minimum, + _In_ ULONG Maximum) +{ + NDIS_STATUS Status; + UNICODE_STRING Keyword; + PNDIS_CONFIGURATION_PARAMETER ConfigurationParameter; + + PAGED_CODE(); + + NdisInitUnicodeString(&Keyword, EntryName); + NdisReadConfiguration(&Status, + &ConfigurationParameter, + ConfigurationHandle, + &Keyword, + NdisParameterInteger); + if (Status != NDIS_STATUS_SUCCESS) + { + TRACE("'%S' request failed, default value %u\n", EntryName, DefaultValue); + + *EntryContext = DefaultValue; + return; + } + + if (ConfigurationParameter->ParameterData.IntegerData >= Minimum && + ConfigurationParameter->ParameterData.IntegerData <= Maximum) + { + *EntryContext = ConfigurationParameter->ParameterData.IntegerData; + } + else + { + WARN("'%S' value out of range\n", EntryName); + + *EntryContext = DefaultValue; + } + + TRACE("Set '%S' to %u\n", EntryName, *EntryContext); +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +DcReadConfiguration( + _In_ PDC21X4_ADAPTER Adapter) +{ + NDIS_STATUS Status; + NDIS_HANDLE ConfigurationHandle; + PUCHAR NetworkAddress; + UINT Length; + ULONG GenericUlong; + + PAGED_CODE(); + + NdisOpenConfiguration(&Status, + &ConfigurationHandle, + Adapter->WrapperConfigurationHandle); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + DcConfigQueryInteger(ConfigurationHandle, + L"SpeedDuplex", + &GenericUlong, + MEDIA_AUTO, + MEDIA_10T, + MEDIA_HMR); + Adapter->DefaultMedia = GenericUlong; + + NdisReadNetworkAddress(&Status, + (PVOID*)&NetworkAddress, + &Length, + ConfigurationHandle); + if ((Status == NDIS_STATUS_SUCCESS) && (Length == ETH_LENGTH_OF_ADDRESS)) + { + if (ETH_IS_MULTICAST(NetworkAddress) || + ETH_IS_EMPTY(NetworkAddress) || + ETH_IS_BROADCAST(NetworkAddress) || + !ETH_IS_LOCALLY_ADMINISTERED(NetworkAddress)) + { + ERR("Invalid software MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", + NetworkAddress[0], + NetworkAddress[1], + NetworkAddress[2], + NetworkAddress[3], + NetworkAddress[4], + NetworkAddress[5]); + } + else + { + INFO("Using software MAC address\n"); + + /* Override the MAC address */ + NdisMoveMemory(Adapter->CurrentMacAddress, NetworkAddress, ETH_LENGTH_OF_ADDRESS); + } + } + + NdisCloseConfiguration(ConfigurationHandle); + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +VOID +DcFreeRcb( + _In_ PDC21X4_ADAPTER Adapter, + _In_ __drv_freesMem(Mem) PDC_RCB Rcb) +{ + PAGED_CODE(); + + if (Rcb->VirtualAddressOriginal) + { + NdisMFreeSharedMemory(Adapter->AdapterHandle, + DC_MEM_BLOCK_SIZE_RCB, + TRUE, /* Cached */ + Rcb->VirtualAddressOriginal, + Rcb->PhysicalAddressOriginal); + } + + if (Rcb->NdisBuffer) + NdisFreeBuffer(Rcb->NdisBuffer); + if (Rcb->Packet) + NdisFreePacket(Rcb->Packet); + + NdisFreeMemory(Rcb, sizeof(*Rcb), 0); +} + +static +CODE_SEG("PAGE") +PDC_RCB +DcAllocateRcb( + _In_ PDC21X4_ADAPTER Adapter) +{ + NDIS_STATUS Status; + PDC_RCB Rcb; + PVOID VirtualAddress; + NDIS_PHYSICAL_ADDRESS PhysicalAddress; + + PAGED_CODE(); + + Status = NdisAllocateMemoryWithTag((PVOID*)&Rcb, sizeof(*Rcb), DC21X4_TAG); + if (Status != NDIS_STATUS_SUCCESS) + return NULL; + NdisZeroMemory(Rcb, sizeof(*Rcb)); + + NdisMAllocateSharedMemory(Adapter->AdapterHandle, + DC_MEM_BLOCK_SIZE_RCB, + TRUE, /* Cached */ + &VirtualAddress, + &PhysicalAddress); + if (!VirtualAddress) + goto Failure; + + /* 32-bit DMA */ + ASSERT(PhysicalAddress.HighPart == 0); + + Rcb->VirtualAddress = ALIGN_UP_POINTER_BY(VirtualAddress, SYSTEM_CACHE_ALIGNMENT_SIZE); + Rcb->PhysicalAddress = ALIGN_UP_BY(PhysicalAddress.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE); + + ASSERT((Rcb->PhysicalAddress % DC_RECEIVE_BUFFER_ALIGNMENT) == 0); + + Rcb->VirtualAddressOriginal = VirtualAddress; + Rcb->PhysicalAddressOriginal.QuadPart = PhysicalAddress.QuadPart; + + NdisAllocatePacket(&Status, &Rcb->Packet, Adapter->PacketPool); + if (Status != NDIS_STATUS_SUCCESS) + goto Failure; + + *DC_RCB_FROM_PACKET(Rcb->Packet) = Rcb; + + NdisAllocateBuffer(&Status, + &Rcb->NdisBuffer, + Adapter->BufferPool, + Rcb->VirtualAddress, + DC_RECEIVE_BLOCK_SIZE); + if (Status != NDIS_STATUS_SUCCESS) + goto Failure; + + NDIS_SET_PACKET_HEADER_SIZE(Rcb->Packet, DC_ETHERNET_HEADER_SIZE); + NdisChainBufferAtFront(Rcb->Packet, Rcb->NdisBuffer); + + PushEntryList(&Adapter->AllocRcbList, &Rcb->AllocListEntry); + + return Rcb; + +Failure: + DcFreeRcb(Adapter, Rcb); + + return NULL; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +DcAllocateReceiveBuffers( + _In_ PDC21X4_ADAPTER Adapter) +{ + ULONG i; + NDIS_STATUS Status; + PDC_RCB Rcb; + + PAGED_CODE(); + + NdisAllocatePacketPool(&Status, + &Adapter->PacketPool, + DC_RECEIVE_BUFFERS_DEFAULT + DC_RECEIVE_BUFFERS_EXTRA, + PROTOCOL_RESERVED_SIZE_IN_PACKET); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + NdisAllocateBufferPool(&Status, + &Adapter->BufferPool, + DC_RECEIVE_BUFFERS_DEFAULT + DC_RECEIVE_BUFFERS_EXTRA); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + /* Allocate RCBs */ + for (i = 0; i < DC_RECEIVE_BUFFERS_DEFAULT; ++i) + { + Rcb = DcAllocateRcb(Adapter); + if (!Rcb) + { + WARN("RCB allocation failed, total buffers %u\n", Adapter->RcbCount); + break; + } + + PushEntryList(&Adapter->UsedRcbList, &Rcb->ListEntry); + + ++Adapter->RcbCount; + } + + if (Adapter->RcbCount < DC_RECEIVE_BUFFERS_MIN) + return NDIS_STATUS_RESOURCES; + + Adapter->RcbFree = Adapter->RcbCount; + + /* Fix up the ring size */ + Adapter->TailRbd = Adapter->HeadRbd + Adapter->RcbCount - 1; + + /* Allocate extra RCBs for receive indication */ + for (i = 0; i < DC_RECEIVE_BUFFERS_EXTRA; ++i) + { + Rcb = DcAllocateRcb(Adapter); + if (!Rcb) + { + WARN("Extra RCB allocation failed\n"); + break; + } + + PushEntryList(&Adapter->FreeRcbList, &Rcb->ListEntry); + } + + Status = NdisAllocateMemoryWithTag((PVOID*)&Adapter->RcbArray, + sizeof(PVOID) * Adapter->RcbCount, + DC21X4_TAG); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +DcAllocateReceiveDescriptors( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_RBD Rbd; + + PAGED_CODE(); + + NdisMAllocateSharedMemory(Adapter->AdapterHandle, + DC_MEM_BLOCK_SIZE_RBD, + FALSE, /* Non-cached */ + &Adapter->RbdOriginal, + &Adapter->RbdPhysOriginal); + if (!Adapter->RbdOriginal) + return NDIS_STATUS_RESOURCES; + + /* 32-bit DMA */ + ASSERT(Adapter->RbdPhysOriginal.HighPart == 0); + + Adapter->RbdPhys = ALIGN_UP_BY(Adapter->RbdPhysOriginal.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE); + + ASSERT((Adapter->RbdPhys % DC_DESCRIPTOR_ALIGNMENT) == 0); + + Rbd = ALIGN_UP_POINTER_BY(Adapter->RbdOriginal, SYSTEM_CACHE_ALIGNMENT_SIZE); + + Adapter->HeadRbd = Rbd; + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +DcAllocateTransmitBlocks( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_TCB Tcb; + NDIS_STATUS Status; + + PAGED_CODE(); + + Status = NdisAllocateMemoryWithTag((PVOID*)&Tcb, + DC_TRANSMIT_BLOCKS * sizeof(*Tcb), + DC21X4_TAG); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + NdisZeroMemory(Tcb, DC_TRANSMIT_BLOCKS * sizeof(*Tcb)); + + Adapter->HeadTcb = Tcb; + Adapter->TailTcb = Tcb + (DC_TRANSMIT_BLOCKS - 1); + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +DcAllocateTransmitDescriptorsAndBuffers( + _In_ PDC21X4_ADAPTER Adapter) +{ + ULONG_PTR BufferVa, BufferPa; + NDIS_STATUS Status; + ULONG i; + + PAGED_CODE(); + + NdisMAllocateSharedMemory(Adapter->AdapterHandle, + DC_MEM_BLOCK_SIZE_TBD_AUX, + FALSE, /* Non-cached */ + &Adapter->TbdOriginal, + &Adapter->TbdPhysOriginal); + if (!Adapter->TbdOriginal) + return NDIS_STATUS_RESOURCES; + + /* 32-bit DMA */ + ASSERT(Adapter->TbdPhysOriginal.HighPart == 0); + + BufferVa = (ULONG_PTR)Adapter->TbdOriginal; + BufferPa = Adapter->TbdPhysOriginal.LowPart; + + BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE); + BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE); + + ASSERT((BufferPa % DC_DESCRIPTOR_ALIGNMENT) == 0); + + Adapter->TbdPhys = (ULONG)BufferPa; + Adapter->HeadTbd = (PDC_TBD)BufferVa; + Adapter->TailTbd = (PDC_TBD)BufferVa + DC_TRANSMIT_DESCRIPTORS - 1; + + BufferVa += sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS; + BufferPa += sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS; + + BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE); + BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE); + + ASSERT((BufferPa % DC_SETUP_FRAME_ALIGNMENT) == 0); + + Adapter->SetupFrame = (PVOID)BufferVa; + Adapter->SetupFramePhys = BufferPa; + + BufferVa += DC_SETUP_FRAME_SIZE; + BufferPa += DC_SETUP_FRAME_SIZE; + + BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE); + BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE); + + for (i = 0; i < DC_LOOPBACK_FRAMES; ++i) + { + Adapter->LoopbackFrame[i] = (PVOID)BufferVa; + Adapter->LoopbackFramePhys[i] = BufferPa; + + BufferVa += DC_LOOPBACK_FRAME_SIZE; + BufferPa += DC_LOOPBACK_FRAME_SIZE; + } + + if (Adapter->Features & DC_HAS_POWER_MANAGEMENT) + { + Status = NdisAllocateMemoryWithTag((PVOID*)&Adapter->SetupFrameSaved, + DC_SETUP_FRAME_SIZE, + DC21X4_TAG); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + } + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +DcAllocateTransmitBuffers( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_COALESCE_BUFFER CoalesceBuffer; + NDIS_STATUS Status; + ULONG i; + + PAGED_CODE(); + + Status = NdisAllocateMemoryWithTag((PVOID*)&CoalesceBuffer, + DC_TRANSMIT_BUFFERS * sizeof(*CoalesceBuffer), + DC21X4_TAG); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + NdisZeroMemory(CoalesceBuffer, DC_TRANSMIT_BUFFERS * sizeof(*CoalesceBuffer)); + + Adapter->CoalesceBuffer = CoalesceBuffer; + + for (i = 0; i < DC_TRANSMIT_BUFFERS; ++i) + { + PVOID VirtualAddress; + NDIS_PHYSICAL_ADDRESS PhysicalAddress; + + NdisMAllocateSharedMemory(Adapter->AdapterHandle, + DC_MEM_BLOCK_SIZE_TX_BUFFER, + FALSE, /* Non-cached */ + &VirtualAddress, + &PhysicalAddress); + if (!VirtualAddress) + continue; + + ASSERT(PhysicalAddress.HighPart == 0); + + CoalesceBuffer->VirtualAddress = + ALIGN_UP_POINTER_BY(VirtualAddress, SYSTEM_CACHE_ALIGNMENT_SIZE); + CoalesceBuffer->PhysicalAddress = + ALIGN_UP_BY(PhysicalAddress.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE); + + Adapter->SendBufferData[i].PhysicalAddress.QuadPart = PhysicalAddress.QuadPart; + Adapter->SendBufferData[i].VirtualAddress = VirtualAddress; + + PushEntryList(&Adapter->SendBufferList, &CoalesceBuffer->ListEntry); + + ++CoalesceBuffer; + } + + if (!Adapter->SendBufferList.Next) + return NDIS_STATUS_RESOURCES; + + return NDIS_STATUS_SUCCESS; +} + +CODE_SEG("PAGE") +VOID +DcInitTxRing( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_TCB Tcb; + PDC_TBD Tbd; + + PAGED_CODE(); + + InitializeListHead(&Adapter->SendQueueList); + + Tcb = Adapter->HeadTcb; + + Adapter->CurrentTcb = Tcb; + Adapter->LastTcb = Tcb; + + Adapter->TcbSlots = DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE; + Adapter->TbdSlots = DC_TRANSMIT_DESCRIPTORS - DC_TBD_RESERVE; + Adapter->LoopbackFrameSlots = DC_LOOPBACK_FRAMES; + Adapter->TcbCompleted = 0; + + Tbd = Adapter->HeadTbd; + Adapter->CurrentTbd = Tbd; + + NdisZeroMemory(Tbd, sizeof(*Tbd) * DC_TRANSMIT_DESCRIPTORS); + + Adapter->TailTbd->Control |= DC_TBD_CONTROL_END_OF_RING; +} + +static +CODE_SEG("PAGE") +VOID +DcCreateRxRing( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_RCB* RcbSlot; + PDC_RCB Rcb; + PDC_RBD Rbd; + PSINGLE_LIST_ENTRY Entry; + + PAGED_CODE(); + + Rbd = Adapter->HeadRbd; + Adapter->CurrentRbd = Rbd; + + RcbSlot = DC_GET_RCB_SLOT(Adapter, Rbd); + Rcb = (PDC_RCB)Adapter->UsedRcbList.Next; + + for (Entry = Adapter->UsedRcbList.Next; + Entry != NULL; + Entry = Entry->Next) + { + Rcb = (PDC_RCB)Entry; + + C_ASSERT((DC_RECEIVE_BUFFER_SIZE % DC_RECEIVE_BUFFER_SIZE_MULTIPLE) == 0); + + Rbd->Address1 = Rcb->PhysicalAddress; + Rbd->Address2 = 0; + Rbd->Control = DC_RECEIVE_BUFFER_SIZE; + Rbd->Status = DC_RBD_STATUS_OWNED; + + *RcbSlot = Rcb; + + ++RcbSlot; + ++Rbd; + Rcb = (PDC_RCB)Rcb->ListEntry.Next; + } + Rbd = Rbd - 1; + Rbd->Control |= DC_RBD_CONTROL_CHAINED; + Rbd->Address2 = Adapter->RbdPhys; + + ASSERT(Rbd == Adapter->TailRbd); +} + +CODE_SEG("PAGE") +VOID +DcInitRxRing( + _In_ PDC21X4_ADAPTER Adapter) +{ + PDC_RBD Rbd; + ULONG i; + + PAGED_CODE(); + + Rbd = Adapter->HeadRbd; + Adapter->CurrentRbd = Rbd; + + for (i = 0; i < Adapter->RcbCount; ++i) + { + Rbd->Control = DC_RECEIVE_BUFFER_SIZE; + Rbd->Status = DC_RBD_STATUS_OWNED; + + ++Rbd; + } + Rbd = Rbd - 1; + Rbd->Control |= DC_RBD_CONTROL_CHAINED; + + ASSERT(Rbd == Adapter->TailRbd); +} + +static +CODE_SEG("PAGE") +NDIS_STATUS +DcAllocateMemory( + _In_ PDC21X4_ADAPTER Adapter) +{ + NDIS_STATUS Status; + + PAGED_CODE(); + + Status = NdisMInitializeScatterGatherDma(Adapter->AdapterHandle, + FALSE, /* 32-bit DMA */ + DC_TRANSMIT_BLOCK_SIZE); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + Status = DcAllocateReceiveDescriptors(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + Status = DcAllocateTransmitBlocks(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + Status = DcAllocateTransmitBuffers(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + Status = DcAllocateTransmitDescriptorsAndBuffers(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + Status = DcAllocateReceiveBuffers(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + return Status; + + NdisAllocateSpinLock(&Adapter->SendLock); + NdisAllocateSpinLock(&Adapter->ReceiveLock); + NdisAllocateSpinLock(&Adapter->ModeLock); + + return NDIS_STATUS_SUCCESS; +} + +static +CODE_SEG("PAGE") +VOID +DcInitTestPacket( + _In_ PDC21X4_ADAPTER Adapter) +{ + ULONG i; + + PAGED_CODE(); + + for (i = 0; i < DC_LOOPBACK_FRAMES; ++i) + { + PETH_HEADER PacketBuffer = Adapter->LoopbackFrame[i]; + + NdisZeroMemory(PacketBuffer, DC_LOOPBACK_FRAME_SIZE); + + /* Destination MAC address */ + NdisMoveMemory(PacketBuffer->Destination, + Adapter->CurrentMacAddress, + ETH_LENGTH_OF_ADDRESS); + + /* Source MAC address */ + NdisMoveMemory(PacketBuffer->Source, + Adapter->CurrentMacAddress, + ETH_LENGTH_OF_ADDRESS); + + ++PacketBuffer; + } +} + +static +CODE_SEG("PAGE") ... 4975 lines suppressed ...