Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dwc_eqos - use ACPI DSM to change TX_CLOCK #29

Merged
merged 2 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ This repository contains drivers for RK35xx-based platforms, with a focus on RK3
|Multimedia codecs||🔴 Not working||
|DSI||🔴 Not working||
|CSI||🔴 Not working||
|GMAC Ethernet|[dwc_eqos](drivers/net/dwc_eqos)|🟡 Partially working|1000Mbps only (gigabit Ethernet only - 10/100 not yet supported)|
|GMAC Ethernet|[dwc_eqos](drivers/net/dwc_eqos)|🟢 Working|Requires latest UEFI (edk2-rk3588 master 2024/01/03 or later).<br> Note that this driver supports the on-chip Ethernet (e.g. it supports the 1GB Ethernet port on Opi5) but does not support the separate Ethernet chip that is added to some higher-tier boards (e.g. it does not support the 2.5GB Ethernet ports on Opi5+).
|UART||🔴 Not working|No OS driver but debugging does work on UART2, being configured by UEFI.|
|GPIO|[rk3xgpio](https://github.com/worproject/Rockchip-Windows-Drivers/tree/master/drivers/gpio)|🟢 Working||
|I2C|[rk3xi2c](https://github.com/worproject/Rockchip-Windows-Drivers/tree/master/drivers/i2c)|🟢 Working||
Expand Down
96 changes: 44 additions & 52 deletions drivers/net/dwc_eqos/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ static auto constexpr QueuesSupported = 1u; // TODO: Support multiple queues?
static auto constexpr InterruptLinkStatus = 0x80000000u;
static auto constexpr InterruptChannel0Status = ~InterruptLinkStatus;

// D637828D-556C-4829-966A-237072F00FF1
static GUID constexpr DsmGuid = { 0xD637828D, 0x556C, 0x4829, 0x96, 0x6A, 0x23, 0x70, 0x72, 0xF0, 0x0F, 0xF1 };
static auto constexpr DsmSetTxClockRevision = 0u;
static auto constexpr DsmSetTxClockIndex = 1u;

// Updated by DevicePerfRegister/DevicePerfUnregister.
static WDFWAITLOCK g_devicesLock = nullptr; // Guards g_devices.
static WDFCOLLECTION g_devices = nullptr; // Guarded by g_devicesLock.
Expand All @@ -52,9 +57,10 @@ struct DeviceContext
MacRegisters* regs;
NETADAPTER adapter;
WDFSPINLOCK queueLock;
WDFWORKITEM updateLinkStateWorkItem;
DEVICE_OBJECT* devicePdo;
WDFINTERRUPT interrupt;
WDFDMAENABLER dma;
WDFWORKITEM linkStateWorkItem;
UINT32 perfCounterDeviceId; // = (regs physical address) >> 4
MacHwFeature0_t feature0;
MacHwFeature1_t feature1;
Expand All @@ -64,13 +70,10 @@ struct DeviceContext
UINT8 currentMacAddress[ETHERNET_LENGTH_OF_ADDRESS];
DeviceConfig config;

// TODO: call ACPI to change phy clock speed.
UINT8 php_grf_clk_con1_gmac_shift; // 0 for GMAC0, 5 for GMAC1.
UINT32* php_grf_clk_con1_regs;

// Mutable.

ChannelStatus_t interruptStatus; // Channel0 + InterruptLinkStatus. Interlocked update.
ChannelStatus_t interruptStatus; // Channel0 + InterruptLinkStatus. Interlocked update.
char updateLinkStateBusy; // 0 = idle, 1 = busy. Interlocked update.

InterruptsWanted interruptsWanted; // Guarded by interrupt lock.
NETPACKETQUEUE rxQueue; // Guarded by queueLock.
Expand Down Expand Up @@ -161,49 +164,50 @@ UpdateLinkState(_In_ DeviceContext const* context)
auto newConfig = oldConfig;
newConfig.FullDuplex = controlStatus.FullDuplex;

// TODO: call ACPI to change phy clock speed.
// Write-enable for bits 3:2, plus constants for bits 3:2.
// Shift left by 0 for GMAC0.
// Shift left by 5 for GMAC1.
UINT32 clockVal;
enum mii_tx_clk_sel_gamc : UINT32
{
mii_tx_clk_sel_gamc_rgmii_002_5 = 0xC0008, // 2.5Mhz = b'10
mii_tx_clk_sel_gamc_rgmii_025 = 0xC000C, // 25Mhz = b'11
mii_tx_clk_sel_gamc_rgmii_125 = 0xC0000, // 125Mhz = b'00
};

UINT32 speed;
switch (controlStatus.Speed)
{
case PhyIfSpeed_2_5M:
speed = 10'000'000u;
clockVal = mii_tx_clk_sel_gamc_rgmii_002_5;
clockVal = 10;
newConfig.PortSelectSpeed = PortSelectSpeed_10M;
break;
case PhyIfSpeed_25M:
speed = 100'000'000u;
clockVal = mii_tx_clk_sel_gamc_rgmii_025;
clockVal = 100;
newConfig.PortSelectSpeed = PortSelectSpeed_100M;
break;
case PhyIfSpeed_125M:
speed = 1'000'000'000u;
clockVal = mii_tx_clk_sel_gamc_rgmii_125;
clockVal = 1000;
newConfig.PortSelectSpeed = PortSelectSpeed_1000M;
break;
default:
speed = 0;
clockVal = mii_tx_clk_sel_gamc_rgmii_125;
clockVal = 1000;
break;
}

if (context->php_grf_clk_con1_regs != nullptr)
ACPI_EVAL_OUTPUT_BUFFER UNALIGNED* returnBufferPtr = nullptr;
ACPI_METHOD_ARGUMENT clockArg = {};
ACPI_METHOD_SET_ARGUMENT_INTEGER((&clockArg), clockVal);
NTSTATUS status = AcpiExecuteDsmFunction(
context->devicePdo,
&DsmGuid,
DsmSetTxClockRevision,
DsmSetTxClockIndex,
&clockArg,
sizeof(clockArg),
&returnBufferPtr);
if (returnBufferPtr != nullptr)
{
clockVal <<= context->php_grf_clk_con1_gmac_shift;
Write32(context->php_grf_clk_con1_regs, clockVal);
TraceWrite("UpdateLinkState-clock", LEVEL_INFO,
TraceLoggingHexInt32(clockVal),
TraceLoggingPointer(context->php_grf_clk_con1_regs, "php_grf_clk_con1_regs"));
ExFreePoolWithTag(returnBufferPtr, ACPI_TAG_EVAL_OUTPUT_BUFFER);
}
if (!NT_SUCCESS(status))
{
TraceWrite("UpdateLinkState-SetTxClock", LEVEL_WARNING,
TraceLoggingNTStatus(status));
}

if (oldConfig.Value32 != newConfig.Value32)
Expand Down Expand Up @@ -389,7 +393,7 @@ DeviceInterruptDpc(
{
context->dpcLinkState += 1;
Read32(&context->regs->Mac_PhyIf_Control_Status); // Clears LinkStatus interrupt.
WdfWorkItemEnqueue(context->linkStateWorkItem);
WdfWorkItemEnqueue(context->updateLinkStateWorkItem);
}

if (newInterruptStatus.Rx || newInterruptStatus.Tx)
Expand Down Expand Up @@ -446,8 +450,12 @@ DeviceLinkStateWorkItem(
{
// PASSIVE_LEVEL, nonpaged (resume path)
auto const context = DeviceGetContext(WdfWorkItemGetParentObject(workItem));
NT_ASSERT(context->linkStateWorkItem == workItem);
UpdateLinkState(context);
NT_ASSERT(context->updateLinkStateWorkItem == workItem);
if (0 == InterlockedExchangeNoFence8(&context->updateLinkStateBusy, 1))
{
UpdateLinkState(context);
InterlockedExchangeNoFence8(&context->updateLinkStateBusy, 0);
}
}

static EVT_NET_ADAPTER_CREATE_TXQUEUE AdapterCreateTxQueue;
Expand Down Expand Up @@ -637,6 +645,7 @@ DeviceD0Entry(

// Clear and then enable interrupts.

NT_ASSERT(ReadNoFence8(&context->updateLinkStateBusy) == 0);
UpdateLinkState(context); // Clears LinkStatus interrupt.
Write32(&context->regs->Dma_Ch[0].Status, ChannelStatus_t(~0u));
DeviceInterruptEnable(context, InterruptsState);
Expand All @@ -663,6 +672,8 @@ DeviceD0Exit(
auto const context = DeviceGetContext(device);

DeviceInterruptDisable(context, InterruptsAll);
WdfWorkItemFlush(context->updateLinkStateWorkItem);
NT_ASSERT(ReadNoFence8(&context->updateLinkStateBusy) == 0);

NT_ASSERT(context->txQueue == nullptr);
NT_ASSERT(context->rxQueue == nullptr);
Expand Down Expand Up @@ -776,20 +787,6 @@ DevicePrepareHardware(
}

context->perfCounterDeviceId = static_cast<UINT32>(descRaw->u.Memory.Start.QuadPart >> 4);

context->php_grf_clk_con1_gmac_shift = 0;
switch (descRaw->u.Memory.Start.QuadPart)
{
case 0xFE1C0000:
context->php_grf_clk_con1_gmac_shift = 5;
__fallthrough;
case 0xFE1B0000:
context->php_grf_clk_con1_regs = static_cast<UINT32*>(MmMapIoSpaceEx(
PHYSICAL_ADDRESS{ 0xFD5B0070, 0 },
sizeof(UINT32),
PAGE_READWRITE | PAGE_NOCACHE));
break;
}
}
break;

Expand Down Expand Up @@ -1255,13 +1252,6 @@ DeviceReleaseHardware(
UNREFERENCED_PARAMETER(resourcesTranslated);

auto const context = DeviceGetContext(device);

if (context->php_grf_clk_con1_regs != nullptr)
{
MmUnmapIoSpace(context->php_grf_clk_con1_regs, sizeof(UINT32));
context->php_grf_clk_con1_regs = nullptr;
}

if (context->regs != nullptr)
{
DeviceReset(context->regs, context->permanentMacAddress);
Expand Down Expand Up @@ -1437,13 +1427,15 @@ DeviceAdd(

WDF_WORKITEM_CONFIG workItemConfig;
WDF_WORKITEM_CONFIG_INIT(&workItemConfig, DeviceLinkStateWorkItem);
status = WdfWorkItemCreate(&workItemConfig, &attributes, &context->linkStateWorkItem);
status = WdfWorkItemCreate(&workItemConfig, &attributes, &context->updateLinkStateWorkItem);
if (!NT_SUCCESS(status))
{
TraceWrite("WdfWorkItemCreate-failed", LEVEL_ERROR,
TraceLoggingNTStatus(status));
goto Done;
}

context->devicePdo = WdfDeviceWdmGetPhysicalDevice(device);
}

// Create adapter.
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/dwc_eqos/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
#include "trace.h"

/*
TODO list:
- Use ACPI DSM to change TX_CLK instead of hard-coding clock address in driver.
Possible areas for improvement:
- Run against network test suites and fix any issues.
- Interrupt moderation and/or other CPU usage improvements.
- Jumbo frames.
- Receive queue memory optimization?
- Configuration in registry (e.g. flow control).
- Configuration in registry (e.g. flow control, speed, duplex).
- Tx segmentation offload.
- Rx segmentation offload.
- Wake-on-LAN.
Expand Down