fix(pcie): account for downstream link capability
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -30,6 +32,82 @@ func TestClassifyGPUFromVendorClass(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPCIeBridgeUsesDownstreamCapability(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
portSpeed string
|
||||
portWidth int
|
||||
endpointSpeed string
|
||||
endpointWidth int
|
||||
wantSpeed string
|
||||
wantWidth int
|
||||
}{
|
||||
{"ConnectX-5 behind Gen4 root port", "Gen4", 16, "Gen3", 8, "Gen3", 8},
|
||||
{"Adaptec SAS behind Gen4 root port", "Gen4", 16, "Gen3", 8, "Gen3", 8},
|
||||
{"I350 behind Gen4 root port", "Gen4", 16, "Gen2", 4, "Gen2", 4},
|
||||
{"faster endpoint remains port-limited", "Gen3", 8, "Gen4", 16, "Gen3", 8},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
gotSpeed := minPCIeLinkSpeed(tc.portSpeed, tc.endpointSpeed)
|
||||
gotWidth := minPositiveInt(tc.portWidth, tc.endpointWidth)
|
||||
if gotSpeed != tc.wantSpeed || gotWidth != tc.wantWidth {
|
||||
t.Fatalf("effective capability = %s x%d, want %s x%d", gotSpeed, gotWidth, tc.wantSpeed, tc.wantWidth)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPCIeBridgeAtEndpointMaximumPasses(t *testing.T) {
|
||||
maxSpeed := minPCIeLinkSpeed("Gen4", "Gen3")
|
||||
maxWidth := minPositiveInt(16, 8)
|
||||
finding := pcieLinkFinding{
|
||||
BDF: "0000:4a:02.0",
|
||||
Description: "Intel root port to ConnectX-5",
|
||||
BeforeSpeed: "Gen3",
|
||||
AfterSpeed: "Gen3",
|
||||
MaxSpeed: maxSpeed,
|
||||
PortMaxSpeed: "Gen4",
|
||||
Width: 8,
|
||||
MaxWidth: maxWidth,
|
||||
PortMaxWidth: 16,
|
||||
Degraded: "Gen3" != maxSpeed,
|
||||
}
|
||||
|
||||
summary := renderPCIeLinkCheckSummary([]pcieLinkFinding{finding})
|
||||
if !strings.Contains(summary, "overall_status=OK") {
|
||||
t.Fatalf("endpoint-limited bridge should pass, got:\n%s", summary)
|
||||
}
|
||||
report := renderPCIeLinkCheckReport([]pcieLinkFinding{finding})
|
||||
if !strings.Contains(report, "limited by downstream device") {
|
||||
t.Fatalf("report should explain the effective maximum, got:\n%s", report)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownstreamPCIeLinkCapabilityFromSysfsTopology(t *testing.T) {
|
||||
bridgeDir := t.TempDir()
|
||||
childDir := filepath.Join(bridgeDir, "0000:4b:00.0")
|
||||
if err := os.Mkdir(childDir, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(childDir, "max_link_speed"), []byte("8.0 GT/s PCIe\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(childDir, "max_link_width"), []byte("8\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// A non-BDF sysfs entry must not influence peer discovery.
|
||||
if err := os.WriteFile(filepath.Join(bridgeDir, "max_link_speed"), []byte("16.0 GT/s PCIe\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
speed, width, ok := downstreamPCIeLinkCapabilityAt(bridgeDir)
|
||||
if !ok || speed != "Gen3" || width != 8 {
|
||||
t.Fatalf("downstream capability = (%q, %d, %v), want (Gen3, 8, true)", speed, width, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderPCIeLinkCheckSummaryDegradedGPU(t *testing.T) {
|
||||
findings := []pcieLinkFinding{
|
||||
{BDF: "0000:0d:00.0", Description: "NVIDIA GPU", IsGPU: true, GPUVendor: "nvidia",
|
||||
|
||||
Reference in New Issue
Block a user