Skip to content

TEST-POWER-MGMT-S3-001: Verify S3 Sleep/Wake State Preservation and Recovery #271

@zarfld

Description

@zarfld

Test Objective

Verify that the IntelAvbFilter driver handles S3 sleep/wake transitions via FilterPause and FilterRestart callbacks, preserves driver state (PHC, TAS/CBS schedules), reinitializes hardware on resume, and maintains >99% success rate across 1000 sleep/wake cycles. Validate FilterPause (<100ms), FilterRestart (<500ms), state preservation, error recovery, and time discontinuity handling.

Traceability

Test Type

  • Type: Functional Test (Power Management, State Preservation)
  • Level: System Test (driver + OS power management)
  • Priority: P0 (Critical) - Required for laptop/mobile deployment
  • Execution: Automated (PowerShell sleep/wake cycles) + Manual (verify state)

Test Environment

Software:

  • Windows 10/11 with IntelAvbFilter.sys installed
  • PowerShell 5.1+ (sleep/wake automation)
  • Driver Verifier enabled (stress testing)

Hardware:

  • Intel I210/I225 NIC (PHC support)
  • Laptop or desktop with S3 support (check via powercfg /a)
  • Wake timer capable (RTC wake or network wake-on-LAN)

Tools:

  • powercfg.exe (trigger sleep/wake)
  • shutdown.exe /h (hibernate)
  • RDTSC (measure FilterPause/FilterRestart latency)
  • ETW (trace NDIS power state transitions)

Prerequisites

  • System supports S3 sleep (powercfg /a shows "Standby (S3)")
  • Driver installed with FilterPause and FilterRestart callbacks implemented
  • PHC initialized and running (time value non-zero)
  • Optional: TAS/CBS schedules configured

Test Procedure

Test Case 1: FilterPause Called on S3 Entry

Steps:

  1. Enable ETW tracing for NDIS filter events
  2. Trigger S3 sleep: rundll32.exe powrprof.dll,SetSuspendState 0,1,0
  3. Verify FilterPause callback invoked
  4. Measure FilterPause latency via RDTSC

Expected Results:

  • ✅ FilterPause called before S3 sleep
  • ✅ FilterPause returns NDIS_STATUS_SUCCESS
  • ✅ FilterPause latency <100ms (Windows requirement)
  • ✅ Driver state saved (PHC time, adjustments, schedules)

ETW Trace Validation:

# Start ETW trace session
$session = New-EtwTraceSession -Name "IntelAvbPower" -LogFileMode Circular

# Add NDIS filter provider
Add-EtwTraceProvider -SessionName "IntelAvbPower" `
    -Guid "{12345678-1234-1234-1234-123456789012}" `  # IntelAvbFilter provider
    -MatchAnyKeyword 0xFF

# Trigger S3 sleep
Write-Host "Triggering S3 sleep..."
rundll32.exe powrprof.dll,SetSuspendState 0,1,0

# Stop trace after wake
Start-Sleep -Seconds 60  # System sleeps, wakes via RTC timer
Stop-EtwTraceSession -Name "IntelAvbPower"

# Parse events
$events = Get-WinEvent -Path "IntelAvbPower.etl" -Oldest

$pauseEvent = $events | Where-Object { $_.Message -match "FilterPause" } | Select-Object -First 1

if (-not $pauseEvent) {
    throw "❌ FilterPause not called during S3 entry"
}

# Verify latency
$pauseLatency = $pauseEvent.Properties[0].Value  # Latency in ms
if ($pauseLatency -gt 100) {
    throw "❌ FilterPause too slow: $pauseLatency ms"
}

Write-Host "✅ FilterPause called on S3 entry (latency: $pauseLatency ms)"

Test Case 2: FilterRestart Called on S3 Resume

Steps:

  1. System wakes from S3 (via RTC wake timer or power button)
  2. Verify FilterRestart callback invoked
  3. Measure FilterRestart latency via RDTSC
  4. Verify hardware reinitialized (BAR0 mapped, PHC running)

Expected Results:

  • ✅ FilterRestart called on S3 resume
  • ✅ FilterRestart returns NDIS_STATUS_SUCCESS
  • ✅ FilterRestart latency <500ms
  • ✅ Hardware reinitialized (PHC running, registers accessible)

Test Code (C++):

void TestFilterRestart() {
    // Trigger S3 sleep/wake cycle
    system("rundll32.exe powrprof.dll,SetSuspendState 0,1,0");
    
    // Wait for wake (system resumes after 60s via RTC timer)
    Sleep(70000);  // 70 seconds
    
    // Verify driver functional after wake
    HANDLE hDevice = OpenAvbDevice();
    
    PHC_TIME_QUERY query = {};
    DWORD bytesReturned;
    BOOL result = DeviceIoControl(hDevice, 0x9C40A010, nullptr, 0,
                                  &query, sizeof(query), &bytesReturned, nullptr);
    
    assert(result == TRUE);  // Driver functional
    assert(query.TimeNs > 0);  // PHC running
    
    printf("✅ FilterRestart successful on S3 resume (PHC time: %llu ns)\n", query.TimeNs);
    CloseHandle(hDevice);
}

Test Case 3: PHC State Preserved Across Sleep/Wake

Steps:

  1. Query PHC time before sleep
  2. Trigger S3 sleep
  3. Wake system
  4. Query PHC time after wake
  5. Calculate time discontinuity (delta)

Expected Results:

  • ✅ PHC time value preserved (or restored to valid range)
  • ✅ Time discontinuity <10s (hardware dependent)
  • ✅ PHC frequency adjustment preserved (FrequencyOffsetPPB)

Test Code (PowerShell):

# Query PHC before sleep
$beforeSleep = Invoke-AvbIoctl -Code 0x9C40A010 -OutputType PHC_TIME_QUERY
$timeBefore = $beforeSleep.TimeNs

Write-Host "PHC time before sleep: $timeBefore ns"

# Trigger S3 sleep
$sleepStart = Get-Date
rundll32.exe powrprof.dll,SetSuspendState 0,1,0

# System wakes (RTC timer or manual)
Start-Sleep -Seconds 70

# Query PHC after wake
$afterWake = Invoke-AvbIoctl -Code 0x9C40A010 -OutputType PHC_TIME_QUERY
$timeAfter = $afterWake.TimeNs

$sleepDuration = (Get-Date) - $sleepStart
$expectedTime = $timeBefore + ($sleepDuration.TotalSeconds * 1e9)  # ns

$discontinuity = [Math]::Abs($timeAfter - $expectedTime) / 1e9  # seconds

Write-Host "PHC time after wake: $timeAfter ns"
Write-Host "Time discontinuity: $discontinuity seconds"

if ($discontinuity -gt 10) {
    Write-Warning "⚠️ Large time discontinuity: $discontinuity s (expected <10s)"
}

Write-Host "✅ PHC state preserved across S3 (discontinuity: $discontinuity s)"

Test Case 4: TAS/CBS Schedules Restored (Best-Effort)

Steps:

  1. Configure TAS schedule before sleep (e.g., 8 time slots)
  2. Trigger S3 sleep
  3. Wake system
  4. Query TAS schedule
  5. Verify schedule restored (or log warning if lost)

Expected Results:

  • ✅ TAS schedule restored if hardware supports state save
  • ⚠️ Warning logged if schedule lost (application reconfigures)
  • ✅ Driver functional even if schedules lost

Test Code (PowerShell):

# Configure TAS schedule before sleep
$schedule = @{
    GateControlList = @(0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F)
    CycleTimeNs = 1000000  # 1ms cycle
}

Invoke-AvbIoctl -Code 0x9C40A040 -Input $schedule  # IOCTL_TAS_CONFIG

# Trigger S3 sleep/wake
rundll32.exe powrprof.dll,SetSuspendState 0,1,0
Start-Sleep -Seconds 70

# Query TAS schedule after wake
$scheduleAfterWake = Invoke-AvbIoctl -Code 0x9C40A044 -OutputType TAS_SCHEDULE

if ($scheduleAfterWake.GateControlList.Count -eq 0) {
    Write-Warning "⚠️ TAS schedule lost during S3 (hardware limitation)"
} else {
    Write-Host "✅ TAS schedule restored: $($scheduleAfterWake.GateControlList.Count) slots"
}

# Verify driver still functional
$phc = Invoke-AvbIoctl -Code 0x9C40A010 -OutputType PHC_TIME_QUERY
assert($phc.TimeNs -gt 0)

Write-Host "✅ Driver functional after S3 (TAS schedule restoration: best-effort)"

Test Case 5: 1000 Sleep/Wake Cycles (Stress Test)

Steps:

  1. Automate 1000 S3 sleep/wake cycles using PowerShell
  2. Monitor for driver failures (FilterRestart errors, BSODs)
  3. Calculate success rate

Expected Results:

  • ✅ Success rate >99% (990/1000 cycles successful)
  • ✅ No BSODs or system crashes
  • ✅ Driver functional after all cycles

Automation Script (PowerShell):

$successCount = 0
$failureCount = 0

for ($i = 1; $i -le 1000; $i++) {
    Write-Host "Sleep/wake cycle $i of 1000..."
    
    # Trigger S3 sleep
    rundll32.exe powrprof.dll,SetSuspendState 0,1,0
    
    # Wait for wake (RTC timer wakes after 10 seconds)
    Start-Sleep -Seconds 15
    
    # Verify driver functional
    try {
        $phc = Invoke-AvbIoctl -Code 0x9C40A010 -OutputType PHC_TIME_QUERY
        
        if ($phc.TimeNs -gt 0) {
            $successCount++
        } else {
            $failureCount++
            Write-Warning "❌ Cycle $i failed (PHC time = 0)"
        }
    } catch {
        $failureCount++
        Write-Warning "❌ Cycle $i failed (IOCTL error: $_)"
    }
    
    # Brief pause between cycles
    Start-Sleep -Seconds 5
}

$successRate = ($successCount / 1000) * 100

Write-Host ""
Write-Host "Sleep/wake cycle results:"
Write-Host "  Success: $successCount / 1000"
Write-Host "  Failure: $failureCount / 1000"
Write-Host "  Success Rate: $successRate%"

if ($successRate -lt 99) {
    throw "❌ Success rate too low: $successRate% (expected >99%)"
}

Write-Host "✅ 1000 sleep/wake cycles passed (success rate: $successRate%)"

Test Case 6: FilterPause Performance (<100ms)

Steps:

  1. Instrument FilterPause callback with RDTSC
  2. Trigger S3 sleep
  3. Measure FilterPause execution time
  4. Verify latency <100ms (1000 iterations)

Expected Results:

  • ✅ Mean FilterPause latency <100ms
  • ✅ P99 latency <150ms
  • ✅ No timeout errors (Windows requirement)

Benchmark Code (C++ in driver):

NDIS_STATUS FilterPause(
    NDIS_HANDLE FilterModuleContext,
    PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters
) {
    UINT64 startTsc = __rdtsc();
    
    PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)FilterModuleContext;
    
    // Save PHC state
    SavePhcState(DeviceContext);
    
    // Save TAS/CBS schedules (best-effort)
    SaveTasSchedules(DeviceContext);
    
    // Mark filter paused
    DeviceContext->FilterPaused = TRUE;
    
    UINT64 endTsc = __rdtsc();
    UINT64 latencyMs = (endTsc - startTsc) / 3000000;  // 3GHz CPU → 3M cycles/ms
    
    // Log latency to ETW
    EventWriteFilterPause(latencyMs);
    
    if (latencyMs > 100) {
        DbgPrint("⚠️ FilterPause slow: %llu ms\n", latencyMs);
    }
    
    return NDIS_STATUS_SUCCESS;  // MUST always succeed
}

Test Case 7: FilterRestart Performance (<500ms)

Steps:

  1. Instrument FilterRestart callback with RDTSC
  2. Wake system from S3
  3. Measure FilterRestart execution time
  4. Verify latency <500ms

Expected Results:

  • ✅ Mean FilterRestart latency <500ms
  • ✅ P99 latency <1000ms
  • ✅ Hardware reinitialized successfully

Benchmark Code (C++ in driver):

NDIS_STATUS FilterRestart(
    NDIS_HANDLE FilterModuleContext,
    PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
) {
    UINT64 startTsc = __rdtsc();
    
    PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)FilterModuleContext;
    
    // Remap BAR0 (may have changed during sleep)
    NDIS_STATUS status = RemapBar0(DeviceContext);
    if (status != NDIS_STATUS_SUCCESS) {
        return status;  // Fail restart if BAR0 unavailable
    }
    
    // Reinitialize PHC
    status = RestorePhcState(DeviceContext);
    if (status != NDIS_STATUS_SUCCESS) {
        DbgPrint("⚠️ PHC restore failed: 0x%X\n", status);
        // Non-fatal - continue
    }
    
    // Restore TAS/CBS schedules (best-effort)
    RestoreTasSchedules(DeviceContext);
    
    // Mark filter running
    DeviceContext->FilterPaused = FALSE;
    
    UINT64 endTsc = __rdtsc();
    UINT64 latencyMs = (endTsc - startTsc) / 3000000;
    
    EventWriteFilterRestart(latencyMs);
    
    if (latencyMs > 500) {
        DbgPrint("⚠️ FilterRestart slow: %llu ms\n", latencyMs);
    }
    
    return NDIS_STATUS_SUCCESS;
}

Test Case 8: Surprise Removal During Sleep

Steps:

  1. Trigger S3 sleep
  2. While system asleep, physically disconnect NIC (USB NIC or Thunderbolt)
  3. Wake system
  4. Verify FilterDetach called (no FilterRestart)

Expected Results:

  • ✅ FilterDetach called instead of FilterRestart
  • ✅ Driver cleans up gracefully
  • ✅ No BSOD or system hang

Test Code (manual test):

# Trigger S3 sleep
Write-Host "Triggering S3 sleep... Disconnect NIC now!"
rundll32.exe powrprof.dll,SetSuspendState 0,1,0

# System wakes
Start-Sleep -Seconds 70

# Verify device removed
$device = Get-PnpDevice | Where-Object { $_.FriendlyName -match "Intel.*225" }

if ($device.Status -eq "OK") {
    throw "❌ Device still present (expected removal)"
}

Write-Host "✅ Surprise removal handled gracefully (FilterDetach called)"

Test Case 9: Error Recovery - FilterRestart Timeout

Steps:

  1. Simulate hardware failure (BAR0 inaccessible) via test hook
  2. Wake system from S3
  3. Verify FilterRestart fails gracefully
  4. Verify device marked unavailable

Expected Results:

  • ✅ FilterRestart returns NDIS_STATUS_FAILURE
  • ✅ Driver marks device unavailable
  • ✅ No BSOD (error logged)

Simulation (test build only):

NDIS_STATUS FilterRestart(...) {
    #ifdef TEST_BUILD
    if (g_SimulateBar0Failure) {
        EventWriteFilterRestartError(NDIS_STATUS_RESOURCES);
        return NDIS_STATUS_RESOURCES;  // Fail restart
    }
    #endif
    
    // Normal restart path...
}

Test Case 10: State Save Buffer Size Validation

Steps:

  1. Configure maximum TAS schedule (16 queues × 1024 time slots)
  2. Trigger S3 sleep
  3. Verify state save buffer sufficient (no truncation)

Expected Results:

  • ✅ State save buffer ≥4KB
  • ✅ No truncation warnings logged
  • ✅ All schedules saved

Test Code (C++ in driver):

#define STATE_SAVE_BUFFER_SIZE (4 * 1024)  // 4KB

NTSTATUS SaveDeviceState(PDEVICE_CONTEXT DeviceContext) {
    PVOID stateBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, 
                                              STATE_SAVE_BUFFER_SIZE, 
                                              'STAS');
    if (!stateBuffer) {
        return STATUS_NO_MEMORY;
    }
    
    ULONG bytesWritten = 0;
    
    // Save PHC state (64 bytes)
    bytesWritten += SavePhcStateToBuffer(stateBuffer, bytesWritten);
    
    // Save TAS schedules (up to 3KB for 16 queues × 1024 slots)
    bytesWritten += SaveTasSchedulesToBuffer(stateBuffer, bytesWritten);
    
    if (bytesWritten > STATE_SAVE_BUFFER_SIZE) {
        DbgPrint("❌ State buffer too small: %lu bytes (need %lu)\n", 
                 STATE_SAVE_BUFFER_SIZE, bytesWritten);
        ExFreePoolWithTag(stateBuffer, 'STAS');
        return STATUS_BUFFER_TOO_SMALL;
    }
    
    DeviceContext->SavedState = stateBuffer;
    DeviceContext->SavedStateSize = bytesWritten;
    
    return STATUS_SUCCESS;
}

Pass/Fail Criteria

Pass Criteria

  • ✅ FilterPause called on S3 entry (Test Case 1)
  • ✅ FilterRestart called on S3 resume (Test Case 2)
  • ✅ PHC state preserved (time discontinuity <10s) (Test Case 3)
  • ✅ TAS/CBS schedules restored (best-effort, warnings logged if lost) (Test Case 4)
  • ✅ 1000 sleep/wake cycles: success rate >99% (Test Case 5)
  • ✅ FilterPause latency <100ms (Test Case 6)
  • ✅ FilterRestart latency <500ms (Test Case 7)
  • ✅ Surprise removal handled gracefully (Test Case 8)
  • ✅ FilterRestart timeout recovers without BSOD (Test Case 9)
  • ✅ State save buffer sufficient (<4KB, no truncation) (Test Case 10)

Fail Criteria

  • ❌ FilterPause not called on S3 entry
  • ❌ FilterRestart not called on S3 resume
  • ❌ PHC time discontinuity >60s (hardware failure)
  • ❌ Success rate <99% in 1000 cycles
  • ❌ FilterPause >100ms (Windows requirement violation)
  • ❌ FilterRestart >1000ms (unacceptable delay)
  • ❌ BSOD on S3 resume
  • ❌ State save buffer overflow (truncated schedules)

Test Data

S3 Sleep Trigger:

rundll32.exe powrprof.dll,SetSuspendState 0,1,0  # Sleep (S3)

RTC Wake Timer (wake after 10 seconds):

powercfg /waketimers  # List wake timers
powercfg /devicequery wake_armed  # Devices that can wake system

Expected Latencies:

  • FilterPause: <100ms (NDIS requirement)
  • FilterRestart: <500ms (acceptable)
  • PHC state save: <10ms
  • PHC state restore: <50ms

State Save Buffer:

  • PHC: 64 bytes (time value + adjustments + calibration)
  • TAS schedules: ~3KB (16 queues × 1024 slots × 1 byte)
  • Total: <4KB

Automation

CI Integration (GitHub Actions - requires wake-capable hardware):

name: Power Management Test (S3)

on: [push, pull_request]

jobs:
  power-mgmt-test:
    runs-on: [self-hosted, windows, wake-capable]  # Custom runner
    steps:
      - uses: actions/checkout@v3
      
      - name: Build Driver
        run: msbuild IntelAvbFilter.sln /p:Configuration=Release /p:Platform=x64
      
      - name: Install Driver
        run: |
          devcon.exe install IntelAvbFilter.inf "ROOT\IntelAvbFilter"
      
      - name: Run 100 S3 Cycles (smoke test)
        run: |
          powershell -ExecutionPolicy Bypass -File tools/s3_stress_test.ps1 -Cycles 100
          
      - name: Verify Results
        run: |
          $results = Get-Content s3_test_results.json | ConvertFrom-Json
          if ($results.SuccessRate -lt 99) {
            throw "❌ S3 test failed: success rate $($results.SuccessRate)%"
          }
          Write-Host "✅ S3 test passed ($($results.SuccessRate)% success rate)"

Dependencies

  • Requires: FilterPause and FilterRestart callbacks implemented
  • Requires: S3-capable hardware (laptop or desktop with suspend support)
  • Requires: PHC state save/restore logic
  • Blocks: Mobile/laptop deployment

Notes

  • NDIS Constraint: FilterPause must always succeed (state save failures non-fatal)
  • Hardware Dependency: TAS/CBS schedule preservation varies by NIC model (I210 may lose schedules, I225 may preserve)
  • Time Discontinuity: PHC time jump expected on S3 (application responsibility to resynchronize)
  • Testing: Requires physical hardware with S3 support (VM testing limited)
  • Driver Verifier: Run with Driver Verifier enabled to catch memory leaks, resource leaks

Related Issues


Version: 1.0
Created: 2025-12-19
Author: Standards Compliance Team

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions