--- a/sys/dev/drm/amd/amdgpu/iceland_ih.c +++ b/sys/dev/drm/amd/amdgpu/iceland_ih.c @@ -185,9 +185,18 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev) { u32 wptr, tmp; wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]); + /* IV entries are 16 bytes: a wptr that is not 16-byte aligned comes + * from a hostile or faulting device and would permanently spin the + * interrupt walk (the 16-byte-stepping rptr can never equal it). + * Normalize with a warn. + */ + if ((wptr & ~IH_RB_WPTR__RB_OVERFLOW_MASK) & 0xF) + dev_warn(adev->dev, "IH wptr not 16-byte aligned: 0x%08X\n", wptr); + wptr &= ~0xF; if (wptr & IH_RB_WPTR__RB_OVERFLOW_MASK) { wptr &= ~IH_RB_WPTR__RB_OVERFLOW_MASK; @@ -196,6 +205,10 @@ * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ + /* derive rptr from the aligned value so a 4-granular wptr + * phase cannot park rptr within 12 bytes of the ring end + * (out-of-bounds decode read) + */ + wptr &= ~0xF; dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask); adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask; (The bounded-walk half of the family fix lives in amdgpu_ih.c — see findings/poc/DF-4887/fix.diff, which already patches the shared walker; the two halves together close the family.)