# DF-4578 — amdgpu_amdkfd_gfx_v8.c: KFD gfx8 backend is dead code on DragonFly; latent enable-day hazards must be guarded

File: `sys/dev/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c` (885 LOC) — pass 2 (GLM 5.3 re-audit).
Sibling of DF-4499 (gfx_v9, same verdict class).

## Build/run/expected

There is nothing to build or run: this file is **not part of any DragonFly build** and its
only call path is compiled out tree-wide. Verification is by source trace + guest
inspection:

```sh
# host (source of truth)
grep -rn "amdgpu_amdkfd_gfx_v8" sys/dev/drm/amd/amdgpu/Makefile sys/dev/drm/amd/Makefile   # no hits => not compiled
grep -rn "define CONFIG_HSA_AMD\|CONFIG_HSA_AMD=" sys/                                      # no hits => KFD never enabled

# guest
pciconf -l | grep 1002      # no ATI hardware present
ls /dev/dri                 # absent
kldstat | grep -i drm       # no drm KLDs loaded
```

Expected: all three confirm dead code / no reachable path (see `env.txt`, `run.log`).

## Liveness proof (why this is dead)

1. `sys/dev/drm/amd/amdgpu/Makefile:155-156` — the amdkfd block adds only
   `SRCS+= amdgpu_amdkfd.c`. `amdgpu_amdkfd_gfx_v8.c` (and `_gfx_v9.c`, and the gfx7
   backend, which does not exist in this tree at all) are **absent from every SRCS
   list**; the lists are explicit, there are no wildcards. The translation unit is
   never compiled.
2. `CONFIG_HSA_AMD` is defined nowhere under `sys/` (grep returns nothing), so
   `amdgpu_amdkfd_init()` (`amdgpu_amdkfd.c:34-47`) sets `kgd2kfd = NULL` and returns
   `-ENOENT`.
3. `amdgpu_amdkfd_device_probe()` (`amdgpu_amdkfd.c:57-71`) returns at
   `if (!kgd2kfd) return;` — `amdgpu_amdkfd_gfx_8_0_get_functions()` (the real one,
   gfx_v8.c:183) is unreachable; the `#ifndef CONFIG_HSA_AMD` stub
   (`amdgpu_amdkfd.c:554-557`) is what links instead.
4. The KFD frontend (`amd/amdkfd/`, `/dev/kfd`, the kfd ioctl entry) does not exist
   anywhere in the DragonFly tree — there is no possible caller of the `kfd2kgd`
   ops table even if the backend were compiled.

## Latent hazards for the day KFD is enabled (fix before flipping CONFIG_HSA_AMD)

Hazards are *not* reachable today (dead code). They are the gfx8 analogues of the
DF-4499 list plus one gfx8-specific NULL-deref:

1. **`kgd_set_pasid_vmid_mapping` (gfx_v8.c:245-270)** — no local `vmid < 16` check.
   `mmATC_VMID0_PASID_MAPPING + vmid` (:260) and `mmIH_VMID_0_LUT + vmid` (:267) are
   16-entry register banks; an out-of-range vmid writes/reads unrelated MMIO.
   `1U << vmid` (:262) is UB for vmid >= 32. Also the `cpu_relax()` status poll
   (:262-263) has no timeout — a hung GPU wedges the calling thread forever.
2. **`get_atc_vmid_pasid_mapping_valid` / `get_atc_vmid_pasid_mapping_pasid`
   (gfx_v8.c:702-720)** — `vmid` is `uint8_t` (0..255) and unchecked:
   `RREG32(mmATC_VMID0_PASID_MAPPING + vmid)` OOB-reads up to 255 dwords past the
   16-entry bank.
3. **`get_fw_version` (gfx_v8.c:778-833)** — each switch case dereferences the
   firmware pointer *before* the NULL check at :828 (`if (hdr == NULL)` can only
   catch `fw->data == NULL`, never `fw == NULL`). Concretely NULL on real parts:
   `adev->gfx.mec2_fw` is NULL on `num_mec == 1` VI ASICs
   (gfx_v8_0.c:2029-2041: TOPAZ/STONEY/default → 1; STONEY is upstream-KFD-supported
   and one probe-list entry away), and `adev->sdma.instance[1].fw` is NULL on
   single-SDMA-instance parts (sdma_v3_0.c:1114-1118: STONEY → 1 instance).
4. **`get_sdma_base_addr` (gfx_v8.c:291-300) / `kgd_hqd_sdma_dump` (:486-492)** —
   `sdma_engine_id`/`sdma_queue_id` (MQD-sourced) and `engine_id`/`queue_id`
   (caller-sourced) are multiplied into MMIO offsets with no bound check
   (`engine_id * SDMA1_REGISTER_OFFSET + queue_id * KFD_VI_SDMA_QUEUE_OFFSET`).
   gfx8 uses multiplication rather than v9's array, so it is an MMIO-offset hazard
   rather than a kernel-memory OOB — same DF-4499 class.
5. **`acquire_queue` (gfx_v8.c:211-220) / `kgd_init_interrupts` (:272-279) /
   `kgd_hqd_load` (:331-332)** — divide by `adev->gfx.mec.num_pipe_per_mec` with no
   zero check (div-by-zero if called before gfx sw_init populates it).
6. Note-only: `set_scratch_backing_va` (:768-776) truncates the 64-bit `va` to 32
   bits in `WREG32(mmSH_HIDDEN_PRIVATE_BASE_VMID, va)` — upstream-identical (scratch
   backing VA is a <4GB aperture offset by KFD design), not a DF divergence.

## Verified-in-bounds (pass-2 negative results, with evidence)

- **MQD walks in `kgd_hqd_load` (:345-360)** — walk 1 `mmCP_MQD_BASE_ADDR..mmCP_HQD_EOP_CONTROL`
  = 0x3245..0x326c (indices 0..39) and walk 2 `mmCP_HQD_EOP_EVENTS..mmCP_HQD_ERROR` =
  0x326f..0x3278 (indices 42..51) against `struct vi_mqd` field positions
  (vi_structs.h:289-340): exact 1:1 layout match, and the struct continues past
  index 51 up to `reserved_t[256]` (:417), so no OOB even for a bare `vi_mqd`.
- **`kgd_hqd_dump` (:387-421)** — count is exactly 54+4 (0x3245..0x327a = 54 regs +
  4 STATIC_THREAD_MGMT); `DUMP_REG` is additionally `WARN_ON_ONCE(i >= HQD_N_REGS)`
  bounds-guarded. No overflow possible.
- **`get_tile_config` (:108-128)** — `ARRAY_SIZE` over the *fixed* arrays
  `tile_mode_array[32]` / `macrotile_mode_array[16]` (amdgpu_gfx.h:175-176), not over
  a pointer; counts are always 32/16 and match the arrays exported.
- **`invalidate_tlbs` (:848-871)** — vmid loop bounded 0..15, `is_kfd_vmid`-gated,
  `1 << vmid` safe for vmid < 16; PASID compare masked with `PASID_MASK` vs uint16_t.
- **`invalidate_tlbs_vmid` (:873-885) / `set_vm_context_page_table_base` (:835-846)** —
  both gate on `amdgpu_amdkfd_is_kfd_vmid()` (compute_vmid_bitmap 0xFF00 → vmid 8..15),
  so `+vmid-8` stays in 0..7 of `mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR` and
  `1 << vmid` in 1<<8..1<<15. Safe.

## Fix

`fix.diff` adds the local bounds/NULL guards (vmid < 16 in the pasid-mapping writer
and both ATC mapping getters, per-case firmware-pointer NULL checks, engine/queue
bounds in the SDMA paths). Authored against the read-only `sys/` tree; not applied.
