# DF-1204 — radeon divide-by-zero in spread-spectrum clock calculation

## Verdict
**NOT REPRODUCED (source-confirmed; hardware+config-gated).** The div-by-zero
is real in both call sites that consume `ss.rate`, and the truncation that
zeroes it is real in both the v2 and v3 parsers of the VBIOS
`ASIC_InternalSS_Info` table. But radeon is not in GENERIC and no AMD/ATI GPU
is present on this QEMU/KVM guest. No runtime trigger; validated by line-level
source trace + single-fix kernel build.

## Mechanism
`radeon_atombios_get_asic_ss_info` (`sys/dev/drm/radeon/radeon_atombios.c:1506`)
parses the VBIOS `ASIC_InternalSS_Info` table. For the engine-clock (SCLK) and
memory-clock (MCLK) spread-spectrum assignments the rate field is read in
"10 Hz" units and then divided by 100 to convert to Hz:

* v2 (`crev==2`), `radeon_atombios.c:1564-1569`:
  ```c
  ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz);
  ...
  if ((crev == 2) &&
      ((id == ASIC_INTERNAL_ENGINE_SS) ||
       (id == ASIC_INTERNAL_MEMORY_SS)))
      ss->rate /= 100;
  ```
* v3, `radeon_atombios.c:1586-1594`:
  ```c
  ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz);
  ...
  if ((id == ASIC_INTERNAL_ENGINE_SS) ||
      (id == ASIC_INTERNAL_MEMORY_SS))
      ss->rate /= 100;
  ```

If the BIOS reports `usSpreadRateIn10Hz < 100` (i.e. < 10 kHz), the integer
divide truncates to **0**. Downstream, that zero flows into:

* `ni_calculate_sclk_params` (`sys/dev/drm/radeon/ni_dpm.c:2044`):
  ```c
  u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
  ```
* `ni_populate_mclk_value` (`ni_dpm.c:2246`):
  ```c
  clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
  ```

Both perform an integer division by `ss.rate` and would trap `#DE` (kernel
panic) on a Cayman/Northern Islands GPU whose VBIOS carries a malformed
spread-spectrum entry. This is the same family of div-by-zero panics as
DF-1128/DF-1143/DF-1166 (fan div-by-zero).

## Why not triggered on this guest
Same as DF-1200: radeon is not in GENERIC, no AMD GPU is present (vgapci0 is
QEMU std VGA), and `ni_dpm` (Cayman/Northern-Islands DPM) only attaches to a
small subset of radeon GPUs that are not emulated by QEMU. Option (d).

## Recommended fix (in `fix.diff`)
Defend the division at the source: in both the v2 and v3 branches of
`radeon_atombios_get_asic_ss_info`, return `false` (no valid SS info) when
`ss->rate < 100` *before* the `/= 100` truncation. This is preferable to
guarding `ni_calculate_sclk_params` / `ni_populate_mclk_value` because it
kills the bad value at the parser boundary, the same way a real BIOS
malfunction should be reported, and the DPM callers already test the boolean
return and disable SS when it is false.

## Build validation
Cumulative kernel build with all 5 fixes applied — `NK_DONE rc=0`. See
`fix_build.log`.

## Reproduce
```
./build.sh    # no-op
./run.sh      # no-op
```
