Skip to content

CI: validate stacked EPR fixes (lint + hosted tulip build) - #5

Open
tyeth wants to merge 3 commits into
fwk-tulip-29169from
test-epr-fixes
Open

tyeth wants to merge 3 commits into
fwk-tulip-29169from
test-epr-fixes

Conversation

@tyeth

@tyeth tyeth commented Oct 20, 2026

Copy link
Copy Markdown
Owner

CI-only branch: the two stacked EPR patches from #1 and #2 plus a hosted-runner build workflow. Opened to get a checkpatch lint run against fwk-tulip-29169. Not for merge.

🤖 Generated with Claude Code

tyeth and others added 3 commits October 20, 2026 23:44
During EPR entry/exit the EC intentionally puts the system into a
transitional clamp state: charger input current is collapsed to 0mA
(learn mode on) and a hard AP throttle is asserted via
update_pmf_events(BIT(PD_PROGRESS_ENTER/EXIT_EPR_MODE), 1). On a
healthy transition this lasts ~1.1s and both are released after the
new contract lands. When the transition fails, two pieces of that
transitional state currently persist beyond the transition:

1. Neither failure handler releases the PMF transition event. The
   normal release path, clear_prochot(), only clears the ENTER event
   when cypd_get_ac_power() > 100W, which is never true after a failed
   EPR entry (the standing SPR contract is at most 100W), so the hard
   throttle outlives the transition it was meant to cover and is left
   to the 3s force_clear_pmf_prochot backstop at best. Release the
   ENTER/EXIT transition events at both points where the flow is
   abandoned: the EPR_MODE_ENTER_FAILED/default branch of
   cypd_update_epr_state(), and the retry-exhausted branch of
   epr_flow_pending_deferred() (the path taken when the EPR event from
   the PD controller never arrives). The failure handler now leaves
   the system in the plain-SPR state (input limit is already restored
   by the existing cypd_update_port_state() call on both paths)
   instead of the mid-transition state.

2. The "EPR fail, do not retry" latch (epr_active = 0xff) is only
   cleared by clear_port_state() on a PORT_DISCONNECT/hard-reset
   response. cypd_update_port_state() deliberately preserves it, and a
   CCG_RESPONSE_PORT_CONNECT does not reset it, so if the disconnect
   response is missed (the same event-loss class the deferred retry
   exists for) or EC RAM outlives a PD controller reset, the latch
   outlives the connection that caused it and the port can never enter
   EPR again. Clear the latch on PORT_CONNECT: a fresh attach is a new
   connection, so the do-not-retry intent (no EPR retry on the
   contract that failed) is preserved while the latch can no longer
   outlive that connection.

Field evidence (FW16 Ryzen AI 300 "tulip", RTX 5070, 240W EPR, EC
tulip-4.0.1): instrumented captures show the system latching into the
transitional state - charger input stuck at ~0/500-800mA, hard
throttle asserted (BIOS runs slow, survives OS reboot), and a port
stuck attach-without-contract where EC_CMD_GET_PD_PORT_STATE returns
zeros and the EC reports "AC not connected". Resets of either or both
PD controllers do not clear it (EC RAM state re-imposes it after every
reset); only a physical AC removal recovers, because only the
PD_PROGRESS_DISCONNECTED path clears the progress/event state. A
healthy reference trace of the same transition (throttle on, input
500mA, ~1.1s, then release) was captured for comparison.

Issue: tyeth/framework-system#1
Telemetry/data: https://github.com/tyeth/fw16-gpu-watchdog
Related: FrameworkComputer/SoftwareFirmwareIssueTracker #160 #193 #241 #243

Compile-untested: no Zephyr build environment was available; changes
were limited to call sites and symbols already used in these files and
verified by read-through.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oned

On boards with the RAA489300 3-level buck (tulip), enter_epr_mode() /
exit_epr_mode() first collapse the charger input current to 0mA (learn
mode on) and assert the PMF transition throttle, then hand off to
buck_ready_for_epr() to sequence the buck mode change before the CCG
EPR command is sent. If the buck readiness check exhausts its retries,
the handler reverts the buck mode and goes idle - but the CCG command
is never sent, so no EPR event ever arrives, and because
epr_flow_pending_deferred() is only scheduled from handle_pd_epr_mode()
(after buck ready), the event-loss backstop never runs either. The
pd_epr_in_progress port bits, the collapsed input current and the
transition throttle are all left standing: a second independent route
into the latched slow state that otherwise only a physical AC removal
clears.

Give the abandonment branch the same cleanup the retry-exhausted
branch of epr_flow_pending_deferred() already performs: clear the
in-progress port bits (keeping the process flags so the existing
restore block in cypd_update_port_state() runs), release the
ENTER/EXIT transition throttle events, and refresh the active charge
port so the input current limit is restored from the standing
contract. The buck mode revert, retry count and timing are unchanged;
on an abandoned exit the standing contract is the still-active EPR
contract and epr_active stays 1, so a later exit attempt remains
possible.

This stacks on "fwk: epr: make a failed EPR transition recoverable
without AC removal" (the two compose: that change covers the failure
paths after the CCG command is sent, this one covers the flow being
abandoned before it is sent).

Issue: tyeth/framework-system#1
Telemetry/data: https://github.com/tyeth/fw16-gpu-watchdog

Compile-untested: no Zephyr build environment was available; the
change uses only symbols already used in this file and was verified by
read-through.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add fork-build.yml: builds the tulip EC image on ubuntu-latest using
zmake with the Zephyr SDK toolchain, Framework zephyr fwk-main, and
the cros cmsis chromeos-main checkout, per docs/zephyr/out_of_chroot.md.
Remove zephyr-build.yml on this branch only: it targets the Framework
self-hosted build server and would queue forever on a fork.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant