# DF-5181 — smu9 SMC-message failures are swallowed (`return 0`), vacating caller error guards and feeding stale `smu9_get_argument()` data into Vega10/12 powerplay

File: `sys/dev/drm/amd/powerplay/smumgr/smu9_smumgr.c` (155 LOC)
Class: CWE-252 (Unchecked Return Code) / CWE-754 (Improper Check for Exceptional Conditions)
Severity: Low · Confidence: certain · Bucket: base:drm (vendored-parity with upstream Linux)

## What the code does

`smu9_send_msg_to_smc()` (smu9_smumgr.c:101-117) and
`smu9_send_msg_to_smc_with_parameter()` (smu9_smumgr.c:128-147) both detect
SMC failure — `ret = smu9_wait_for_response(hwmgr); if (ret != 1)` — but only
`pr_err()` it and then **unconditionally `return 0`** (:116, :146).

The wait itself is bounded (`phm_wait_for_register_unequal`,
smu_helper.c:151-173, `hwmgr->usec_timeout` = AMD_MAX_USEC_TIMEOUT = 200 ms,
hwmgr.c:85) so there is no hang; each wedged message burns two full timeouts
(pre-send drain at :106/:134 + real wait at :112/:142).

## Consequence (why the return value matters)

Callers were written expecting a propagated error:

- `vega10_smumgr.c:147-150`:
  `PP_ASSERT_WITH_CODE(!smu9_send_msg_to_smc(hwmgr, PPSMC_MSG_GetDriverIfVersion), "Attempt to get SMC IF Version Number Failed!", return -EINVAL)`
  — with the always-0 return this guard can NEVER fire; :151 then reads
  `smc_driver_if_version = smu9_get_argument(hwmgr)` from C2PMSG_82, which was
  **not** overwritten by the failed message (only the response reg C2PMSG_90 is
  zeroed at :108/:136) → stale value flows into the version check at :160.
- `vega12_smumgr.c:52-57` writes the condition explicitly as
  `smu9_send_msg_to_smc_with_parameter(...) == 0` with the message
  "Attempt to Set Dram Addr High Failed!" — dead guard today.
- `vega10_smumgr.c:47-58` (`vega10_copy_table_from_smc`): three unchecked
  sends (SetDriverDramAddrHigh/Low + TransferTableSmu2Dram) followed by
  `memcpy(table, priv->smu_tables.entry[table_id].table, ...size)` — on a
  failed transfer the driver memcpy's the previous contents of the driver-side
  buffer and the powerplay state machine consumes stale table data.
- `vega10_smumgr.c:107-108`: stale `features_enabled` bitmap drives
  `vega10_is_dpm_running()` (:113-123) decisions.

No memory-unsafe sink was found: all table-copy sizes are driver-fixed at
allocation (`vega10_smumgr.c:45-46`, `:57-58`), never derived from
`smu9_get_argument()`. Impact ceiling is wrong power/clock/DPM decisions from
stale SMU state.

## Reproduce

Requires Vega10/Vega12 silicon with a hung/mismatched SMC firmware — **not
testable on the audit QEMU guest** (virt hardware, no AMD dGPU). The defect is
a source-semantics property fully demonstrated by citation above; no runtime
verification was attempted (status `untested`). Fix validation likewise
`not_testable` — see VERDICT.md.

## Fix

`fix.diff` in this directory: propagate `return (ret == 1) ? 0 : -EIO;` in both
send functions. Caller-compatible (vega10/vega12 guards already treat 0 as
success). Matches the direction upstream Linux eventually needs; this file is a
verbatim port of upstream `smu9_smumgr.c`, so the fix owner is upstream
drm-amd.
