Skip to content

drm/asahi: g17: five small fixes (soft faults, recovery blame, torn snapshots, signalled fences, HIGH priority) - #391

Merged
RyanTheTide merged 5 commits into
aurora-silicon:integration/aurorafrom
jgoyvaerts:m4pro/g17-generic
Oct 23, 2026
Merged

RyanTheTide merged 5 commits into
aurora-silicon:integration/aurorafrom
jgoyvaerts:m4pro/g17-generic

Conversation

@jgoyvaerts

Copy link
Copy Markdown

Five small G17 fixes that are not specific to any SoC. We found them running the M4 Pro (T6040, 25G83 firmware) on the G17 backend in our own tree; none of them touches T6040 code, and they apply to the T8140 path as it is on integration/aurora.

  • Do not advertise soft faults. DRM_ASAHI_FEATURE_SOFT_FAULTS was set whenever the fault_control parameter kept its default, but the G17 runtime never programs fault_control into the firmware (only the G13/G14 init data does). Mesa trusts the bit: it points out-of-bounds vec3/vec4 vertex fetches at address 0 and skips bounds checks on bounded constant loads. On the M4 Pro those reads returned non-zero data, and every robustness2 rgba32 vertex_attribute_fetch case failed. A new Gpu::supports_soft_faults() keeps the old answer for G13/G14; G17 says no.
  • Reread a torn borrowed render snapshot. poll() already gives a snapshot that straddles a firmware cursor update one reread and then a retry. poll_observed(), which finishes a snapshot taken while the pair was borrowed, returned the EIO directly, so one torn sample quarantined the pair and the client saw a lost device. It now falls back to poll(), which takes a fresh snapshot.
  • Do not fail a blamed render that attribution cleared. Recovery attribution can move the firmware's blame: a blamed render that had not started while others had, or a recovery with no culprit, is innocent. service() still failed the blamed render's oldest packet with EIO. On the M4 Pro the firmware blamed the compositor's not-yet-started full-screen render while a Vulkan test faulted in another process; the compositor aborted and took the session down. classify() now also returns whether the blamed QID is still guilty, and only then is its render failed. Where ownership is unknown, the old behaviour stays. Each recovery logs its reason, blamed queue and decision.
  • Skip already-signalled successful input fences. Nearly every desktop render carries input fences that signalled long before the submit. Each one became a scheduler dependency, so the render went through the drm_sched worker instead of inline publication: 0.25-0.5 ms before the GPU started, against about 0.07 ms for the ioctl. A fence that signalled without error orders nothing and has no error to consume, like the completed frontier producers the loop already skips. Pending and failed inputs are kept as before.
  • Allow HIGH queue priority with CAP_SYS_NICE or DRM master, as amdgpu and panthor do, and refuse it with EACCES otherwise. REALTIME stays reserved. On G17, HIGH maps to firmware priority class 1 (the class the G13 tables use for HIGH) with the user classes' policy word. Adds drm::File::is_current_master(). Today Mesa's GL driver advertises HIGH but creates MEDIUM, and the Vulkan driver refuses HIGH; both can follow once this is in.

Hardware tested on: Apple MacBook Pro (16-inch, M4 Pro, 2024), J616s / T6040, 25G83 GPU firmware, on our daily tree, which runs the T6040 on this G17 backend (that support is not part of this PR). All five commits have been in our daily kernel since 2026-10-19/20, and on Linux 7.3 (integration/aurora ed55042 plus our series) since 2026-10-22.

How tested:

  • Soft faults: the dEQP-VK robustness2 rgba32 vertex_attribute_fetch cases failed with the bit set and pass with soft faults off.
  • Torn snapshot and cleared blame: both failures were found during a Vulkan conformance run beside the desktop, where innocent clients (the compositor among them) got lost-device errors with no GPU fault of their own. The desktop has run on both fixes daily since.
  • Signalled fences: submit-to-start latency measured on the desktop, as above.
  • HIGH priority: no client on our machine asks for HIGH yet, so the class-1 firmware path has not carried real work.

Not tested / limits:

  • None of this has run on a T8140 (Neo) or on G13/G14. The HIGH check is in the common queue_create, so G13/G14 accept HIGH too and use their existing priority-1 pipes.
  • No KUnit test for classify(): the recovery attribution path has none today, and I can't run KUnit here.

Relation to other PRs: based on integration/aurora (1fb1fa9), which includes #377. Merges cleanly with #390 (checked with git merge-tree against its head 8744e94). Our T6040 GPU support itself is not in this PR; it waits for #367.

Build and checks: W=1 build of drivers/gpu/drm/asahi with defconfig + asahi.config (LLVM=1): no new warnings (the six fetch_update deprecation notices are in the base). checkpatch --strict: clean except one 117-column line, the existing classify() signature, which only changes its return type and stays in the file's style. rustfmt leaves the changed g17 files' formatting as in the base.

🤖 Generated with Claude Code

DRM_ASAHI_FEATURE_SOFT_FAULTS was set whenever the fault_control module
parameter kept its default, but the G17 runtime never programs
fault_control into the firmware, so unmapped GPU reads are not
guaranteed to return zero. Mesa trusts the bit: it points out-of-bounds
vec3/vec4 vertex fetches at address 0 and skips the bounds check on
bounded constant loads. On the M4 Pro those reads returned non-zero
data and every robustness2 rgba32 vertex_attribute_fetch case failed;
they pass with soft faults disabled in Mesa.

Ask the GPU backend instead; G17 reports none.

Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
poll() knows that individually sampled cursor words can straddle a
firmware update: an implausible snapshot gets one immediate reread, and
a second implausible one is only a retry. poll_observed(), which
finishes a snapshot taken while the pair was borrowed, returned the
plausibility check's EIO directly, so one torn sample quarantined the
pair and the client saw a lost device. Under load (a Vulkan conformance
run beside the desktop) this failed innocent clients, the compositor's
full-screen composite among them, with no GPU fault and no recovery.

Fall back to poll() when the borrowed snapshot does not pass.

Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
GPU recovery classifies guilt from the firmware's recovery table and its
blamed QID, and attribution can move that blame: a blamed render that
had not started while other renders had (or with no culprit at all) is
innocent. service() still failed the blamed render's oldest packet with
EIO. On the M4 Pro the firmware blamed the compositor's not-yet-started
full-screen render while a Vulkan test faulted in another process: the
compositor saw a lost device and aborted, taking the session down.

classify() now also returns whether the blamed QID is still guilty after
attribution; only then is its render failed. Otherwise its work is
spared like every other innocent VM's. Log each recovery's reason,
blamed queue and decision.

Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
Almost every desktop render carries input fences, nearly all of them
buffer fences that signalled long before the submit. Each one still
became a scheduler dependency, so the render went through the drm_sched
worker instead of inline publication: 0.25-0.5 ms before the GPU
started, against about 0.07 ms for the submit ioctl itself.

A fence that signalled without error orders nothing and has no error
left to consume, exactly like the completed frontier producers the loop
already skips. Skip it; a pending or failed input is kept and checked
as before.

Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
queue_create refused DRM_ASAHI_PRIORITY_HIGH with EINVAL (a TODO to
allow it with CAP_SYS_NICE), and the G17 scheduling table had no HIGH
profile. Mesa works around it: the GL driver advertises HIGH context
priority but creates a MEDIUM queue, and the Vulkan driver refuses HIGH
global priority until the kernel accepts it.

Allow HIGH for callers with CAP_SYS_NICE or the DRM master, as amdgpu
and panthor do for raised queue priority, and refuse it with EACCES
otherwise so userspace can fall back. REALTIME stays reserved. Add
drm::File::is_current_master() for the check. On G17 HIGH maps to
firmware priority class 1, the class the G13 tables use for HIGH, with
the policy word of the user classes; its work rings are already set up
at boot.

The check is in the common queue_create, so the G13 and G14 SoCs accept
HIGH too and submit it on their existing priority-1 pipes. That is
untested there.

Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
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.

2 participants