⬢ DragonFlyBSD Kernel Audit
DF-5223 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/radeon/rv770_dma.c b/sys/dev/drm/radeon/rv770_dma.c
index acff6e09..16c2616c 100644
--- a/sys/dev/drm/radeon/rv770_dma.c
+++ b/sys/dev/drm/radeon/rv770_dma.c
@@ -56,7 +56,17 @@ struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev,
 
 	size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
 	num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFF);
-	r = radeon_ring_lock(rdev, ring, num_loops * 5 + 8);
+	/* Reserve space for everything radeon_sync_rings() may emit on THIS
+	 * ring (up to RADEON_NUM_SYNCS semaphore waits, 3 dwords each on the
+	 * r6xx/r7xx DMA ring) plus the 5-dword fence emit.  The old "+8"
+	 * covered exactly one semaphore wait; with two pending cross-ring
+	 * fences (GFX + UVD) the over-emission wrote 16 dwords past the
+	 * reserved window (radeon_ring_write() only DRM_ERRORs and writes
+	 * anyway, radeon.h:2710-2716), overwriting un-executed ring commands
+	 * when the ring is tight.  Mirrors the IB-path accounting
+	 * (radeon_ib.c reserves 64 + RADEON_NUM_SYNCS * 8, radeon_ib.c:135).
+	 */
+	r = radeon_ring_lock(rdev, ring, num_loops * 5 + 8 + RADEON_NUM_SYNCS * 3);
 	if (r) {
 		DRM_ERROR("radeon: moving bo (%d).\n", r);
 		radeon_sync_free(rdev, &sync, NULL);