Floor shows a staged BIOS update from the start of WinPE; NIC speed past 4.29 Gb/s

- winpe-status-push.ps1: check-bios.cmd stages the firmware update before
  the imaging menu, but startnet's 'BIOS firmware update' push only comes
  at the end of WinPE, so builds showed a plain 'Applying image' for the
  whole apply. The first push now reports the staged update when
  X:\bios-fired.flag exists, and the floor shows 'Applying image - BIOS
  update staged' (do not power off during the next reboot). Also: CIM
  fallback for the serial where wmic is missing, and standard/engineer
  always report 5 steps.
- Network pill: cdc_ncm (e.g. the WisdPI RTL8157 5G adapter) keeps link
  speed in a 32-bit bits/s field, so 5 Gb/s reads 705 Mb/s; show the real
  speed with a note.

Tested in the win11 VM (with and without the BIOS flag, and the late
startnet push).
This commit is contained in:
cproudlock
2026-10-14 16:56:46 -04:00
parent 0d69222f85
commit 454e30ff6f
4 changed files with 35 additions and 5 deletions

View File

@@ -22,6 +22,11 @@ import config
STALE_SECONDS = 20 * 60 # the watch timer runs every 5 min
SYS_NET = "/sys/class/net"
# cdc_ncm (the generic USB NIC driver, e.g. a WisdPI RTL8157 5G adapter on a
# kernel whose r8152 does not know the chip) keeps the link speed as a 32-bit
# bits-per-second value, so multi-gig links wrap: 5 Gb/s reads 705 Mb/s and
# 10 Gb/s reads 1410 Mb/s.
CDC_NCM_WRAPPED = {705: 5000, 1410: 10000}
def _read(path):
@@ -102,13 +107,19 @@ def _kernel_view():
speed = speed if speed > 0 else None
except ValueError:
speed = None
notes = []
driver = os.path.basename(os.path.realpath(os.path.join(base, "device", "driver")))
if driver == "cdc_ncm" and speed in CDC_NCM_WRAPPED:
notes.append(f"Link {CDC_NCM_WRAPPED[speed] // 1000} Gb/s (the cdc_ncm driver reports "
f"{speed} Mb/s: its 32-bit speed counter wraps above 4.29 Gb/s)")
speed = CDC_NCM_WRAPPED[speed]
out.append({
"iface": name, "mac": mac,
"role": roles.get(name) or roles.get(mac) or "other",
"link": "up" if oper == "up" else "down",
"speed_mbps": speed if oper == "up" else None,
"addrs": addrs.get(name, []),
"verdict": None, "evidence": [],
"verdict": None, "evidence": [], "notes": notes,
"dnsmasq_bound": (None if bound is None else (name in bound or "*" in bound)),
})
return out
@@ -170,7 +181,7 @@ def status():
i = dict(i)
k = live.get(i.get("iface"))
if k: # link and addresses are cheap to read now; keep the check's verdict
i.update(link=k["link"], speed_mbps=k["speed_mbps"], addrs=k["addrs"])
i.update(link=k["link"], speed_mbps=k["speed_mbps"], addrs=k["addrs"], notes=k["notes"])
if k["dnsmasq_bound"] is not None:
i["dnsmasq_bound"] = k["dnsmasq_bound"]
if stale:

View File

@@ -81,7 +81,11 @@
{% if stage_idx == 4 and s.status != 'failed' %}{% set warn = True %}{% endif %}
{% else %}
{% set friendly = (desk_stage_labels if s.pctype in desk_kind else stage_labels).get(stage_idx, ('Stage ' ~ stage_idx, '')) %}
{% if stage_idx == 1 and s.current_stage and 'bios' in s.current_stage|lower %}
{% if stage_idx == 1 and s.current_stage and 'bios update staged' in s.current_stage|lower %}
{% set friendly = ('Applying image - BIOS update staged',
'WinPE staged a firmware update for this model. It flashes during the reboot after the image is applied: do NOT power off then.') %}
{% set warn = True %}
{% elif stage_idx == 1 and s.current_stage and 'bios' in s.current_stage|lower %}
{% set friendly = ('Updating BIOS: do not power off',
'WinPE detected a firmware update for this model. Do NOT power off until the next reboot. Imaging continues afterward.') %}
{% set warn = True %}

View File

@@ -30,7 +30,7 @@
{{ 'Up' if i.link == 'up' else 'No link' }}{% if i.speed_mbps %}, {% if i.speed_mbps >= 1000 %}{{ (i.speed_mbps // 1000) if i.speed_mbps % 1000 == 0 else (i.speed_mbps / 1000) | round(1) }} Gb/s{% else %}{{ i.speed_mbps }} Mb/s{% endif %}{% endif %}
{% if i.addrs %}<span class="mono">{{ i.addrs | join(', ') }}</span>{% endif %}
{% if i.dnsmasq_bound is not none %}<br>DHCP/PXE {{ 'served here' if i.dnsmasq_bound else 'not served here' }}{% endif %}
{% for e in i.evidence %}<br>{{ e }}{% endfor %}
{% for e in i.evidence %}<br>{{ e }}{% endfor %}{% for n in i.notes or [] %}<br><span class="sub">{{ n }}</span>{% endfor %}
</div>
</div>
{% else %}