# DF-4051 — nfe_stop() vs nfe_tick() callout AB-BA deadlock (nfe(4) instance of the DF-3715/4025/4046 family)

## What

`sys/dev/netif/nfe/if_nfe.c`:

- `nfe_attach` arms one callout with plain **non-MP** `callout_init(&sc->sc_tick_ch)`
  (`if_nfe.c:636`).
- `nfe_tick` (`if_nfe.c:2181-2193`) **blocks** acquiring the driver serializer
  (`lwkt_serialize_enter`, `:2187`), does `mii_tick`, then **re-arms itself
  UNCONDITIONALLY while holding it** (`callout_reset(&sc->sc_tick_ch, hz,
  nfe_tick, sc)`, `:2190` — no IFF_RUNNING gate).
- `nfe_stop` (`if_nfe.c:1585-1640`) issues the **synchronous**
  `callout_stop(&sc->sc_tick_ch)` (`:1593`) as its **first** action after
  `ASSERT_SERIALIZED` (`:1591`) — i.e. **while holding** that serializer.
- DragonFly `callout_stop()` is synchronous (`sys/kern/kern_timeout.c:1091-1093`
  → `_callout_cancel_or_stop(..., sync=1)`; the `ssleep "costp"` wait at
  `kern_timeout.c:920`): it waits for an INPROG callback to finish.

A `nfe_tick` dequeued by a softclock thread and parked in
`lwkt_serialize_enter` therefore deadlocks against the stopper: both threads
wedge permanently, the interface serializer is never released (every later
ioctl / if_start on nfeX blocks), and the affected softclock stops delivering
**all** callouts on that CPU.

Reachable from every down/detach/reinit path racing the 1 Hz tick:
`nfe_detach :669-672`, `nfe_shutdown :705-708`, `nfe_suspend :716-719`,
`nfe_ioctl` SIOCSIFFLAGS `:1025-1027`, and `nfe_init :1446` (nfe_stop is its
first statement) — itself reachable from SIOCSIFMTU `:1005-1007`,
SIOCSIFCAP `:1049-1051`, `nfe_resume :730-732`, `nfe_watchdog :1431`.

## Reproduce (guest, root)

```
scp -F dfbsd-qemu/config nfereplica.c Makefile dfbsd:/root/nfereplica/
ssh -F dfbsd-qemu/config dfbsd 'cd /root/nfereplica && make'
kldload /root/nfereplica/nfereplica.ko
sysctl kern.nfereplica.arm=1      # arm the nfe_tick replica (1-tick period)
sleep 2
(sysctl kern.nfereplica.stop=1 &) # nfe_stop shape: NEVER returns
sleep 6; dmesg | grep nfereplica | tail -4
ps -o pid,stat,wchan,command -ax | grep -E "stop=1|softclock" | grep -v grep
```

## Expected output (observed, run.log + serial_console.txt)

```
nfereplica: nfe_tick parked on our serializer (fired=201 ran=200) - entering callout_stop()
nfereplica: IF THIS IS THE LAST nfereplica LINE, AB-BA DEADLOCK IS PROVEN
...
   974 D2     costp    sysctl kern.nfereplica.stop=1     <- kern_timeout.c:920
    -1 B3     slize    (softclock 3)                     <- lwkt_serialize_enter
```

The stopper sits in `costp` across ≥2 samples minutes apart (permanent), the
console ends at the marker line, and the guest cannot shut down cleanly —
`vm.sh reset with-src` is the documented recovery.

## Hardware gating / family convention

The guest has **no NVIDIA nForce MCP NIC** (`pciconf -l` shows none; QEMU
does not emulate forcedeth), so the in-driver instance cannot be triggered at
runtime; per the DF-4025/DF-4046 family convention the persisted status is
`inconclusive` with the mechanism PROVEN by this deterministic replica of
if_nfe.c's exact callout/serializer protocol.
