# DF-4728 — aureal: AC97 codec protocol busy-waits up to ~0.45 s per register and ignores timeouts (au_wrcd still writes and reports success)

**File:** `sys/dev/sound/pci/aureal.c` · **Severity:** Info · **Bucket:** base:dev · **Confidence:** certain

## Root cause (path:line)

### `au_rdcd()` — `aureal.c:126-143`
```c
	while (j<50) {
		i=au_rd(au, 0, AU_REG_CODECIO, 4);
		if ((i & 0x00ff0000) == (regno | 0x00800000)) break;
		DELAY(j * 200 + 2000);          /* busy-wait, grows with j */
		j++;
	}
	if (j==50) printf(... timeout ...);
	return i & AU_CDC_DATAMASK;          /* returns last (garbage) read anyway */
```
Worst case per register: Σ_{j=0..49}(200j+2000) = **245,000+100,000 ≈ 0.345 s**
of busy `DELAY` (preemption-less spin) — and on timeout it returns whatever
the last read was, indistinguishable from real data.

### `au_wrcd()` — `aureal.c:145-169`
```c
	do {
		while (j<50 && (i & AU_CDC_WROK) == 0) {
			i=au_rd(au, 0, AU_REG_CODECST, 4);
			DELAY(2000);           /* 50 x 2ms = 100 ms busy */
			j++;
		}
		if (j==50) printf(... timeout ...);
		au_wr(au, 0, AU_REG_CODECIO, (regno<<16) | AU_CDC_REGSET | data, 4);
		tries++;
	} while (0);                          /* retry loop compiled out */
	return 0;                             /* success reported regardless */
```
On WROK timeout it **still writes** the codec register and **returns 0**
(success) — a wedged codec silently yields an unusable mixer that the frame-
work believes initialized.

## Impact

With a present-but-unresponsive codec (failing card, bus fault), `mixer_init`
(`aureal.c:634`) issues ~90-100 codec ops → up to **tens of seconds of
continuous busy-spin at attach** (giant-held, interrupt-livid boot path), and
runtime `/dev/mixerN` reads by unprivileged users can each spin ~0.35 s.
No memory-safety issue — availability/hardening only. Info severity;
hardware-gated; driver additionally not in default builds (DF-4724 notes).

## Verification

Hardware-gated; code-path audit only (DELAY is a busy spin: `sys/sys/systm.h`).

## Recommended fix

Cap the total wait budget, return failure on timeout (propagate
`mixer_init` failure so attach unwinds), and skip the write when WROK never
asserted. See fix.diff.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
