# DF-4732 — amdgpu_dm_irq.c takes a sleepable lockmgr lock from the GPU interrupt dispatch path (DragonFly port)

- **File**: `sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c`
- **Severity**: Low (local DoS ceiling — panic/deadlock; requires AMD GPU + interrupt-vs-suspend race)
- **Confidence**: likely (protocol violation is code-certain; runtime manifestation reasoned, not demonstrated — no AMD hardware on the audit guest)

## The defect

On this port `spinlock_t` is `struct lock` and `spin_lock_irqsave()` is
`local_irq_save(flags); lockmgr(lock, LK_EXCLUSIVE);`
(`sys/dev/drm/include/linux/spinlock_types.h:38`, `sys/dev/drm/include/linux/spinlock.h:75-78`)
— a **sleepable** lock acquired with hardware interrupts force-disabled on the
local CPU.

`DM_IRQ_TABLE_LOCK` (`amdgpu_dm_irq.c:50-54`) is taken from the GPU ISR
dispatch chain:

```
request_irq() -> bus_setup_intr(..., INTR_MPSAFE, linux_irq_handler, ..., &serializer)
                                                      (sys/dev/drm/linux_irq.c:84-86 — serialized ithread)
  -> amdgpu_irq_handler (amdgpu_irq.c:189)
  -> amdgpu_irq_dispatch -> .process = amdgpu_dm_irq_handler (amdgpu_dm_irq.c:588-601, :476-495)
  -> amdgpu_dm_irq_immediate_work (:452)  -- lockmgr LK_EXCLUSIVE in ithread ctx
  -> amdgpu_dm_irq_schedule_work (:427)   -- same
```

Process-context holders keep this lock for non-trivial durations:
`amdgpu_dm_irq_suspend` (`:345-363`) holds it across `dc_interrupt_set()` MMIO
read-modify-writes; `amdgpu_dm_irq_immediate_work` itself holds it while
dispatching every high-context handler (`:464`) — vblank/pageflip work.

On contention the serialized ithread attempts to sleep inside `lockmgr` while
holding the interrupt serializer and with `cpu_disable_intr()` active from
`local_irq_save` — sleeping in an ithread / with a serializer held is illegal
on DragonFly (panic/deadlock). Upstream Linux uses a true spinlock here, where
`spin_lock_irqsave` in hardirq context is correct.

## Why not reproduced

The audit guest has no AMD GPU (env.txt). Building amdgpu into the guest kernel
cannot conjure the hardware; the ISR path never runs. Static proof of the
acquisition chain is in VERDICT.md.

## Fix

`fix.diff` converts `irq_handler_list_table_lock` to a true DragonFly
`struct spinlock` (crit_enter + spin_lock in the table-lock macros), matching
upstream's non-sleeping irqsave semantics. Not applied to `sys/` (read-only
audit tree).
