diff --git a/sys/dev/drm/radeon/radeon.h b/sys/dev/drm/radeon/radeon.h index 1111111..2222222 100644 --- a/sys/dev/drm/radeon/radeon.h +++ b/sys/dev/drm/radeon/radeon.h @@ -2404,6 +2404,7 @@ struct radeon_device { bool needs_reset, in_reset; bool fictitious_range_registered; struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES]; + struct lock surface_regs_lock; /* serializes get/clear_surface_reg */ const struct firmware *me_fw; /* all family ME firmware */ const struct firmware *pfp_fw; /* r6/700 PFP firmware */ const struct firmware *rlc_fw; /* r6/700 RLC firmware */ diff --git a/sys/dev/drm/radeon/radeon_device.c b/sys/dev/drm/radeon/radeon_device.c index 1111111..2222222 100644 --- a/sys/dev/drm/radeon/radeon_device.c +++ b/sys/dev/drm/radeon/radeon_device.c @@ -1319,6 +1319,7 @@ int radeon_device_init(struct radeon_device *rdev, atomic_set(&rdev->ih.lock, 0); lockinit(&rdev->gem.mutex, "radeon_gemmtx", 0, LK_CANRECURSE); + lockinit(&rdev->surface_regs_lock, "radeon_surflk", 0, 0); lockinit(&rdev->pm.mutex, "drdpmm", 0, LK_CANRECURSE); lockinit(&rdev->gpu_clock_mutex, "radeon_clockmtx", 0, LK_CANRECURSE); lockinit(&rdev->srbm_mutex, "radeon_srbm_mutex", 0, LK_CANRECURSE); diff --git a/sys/dev/drm/radeon/radeon_object.c b/sys/dev/drm/radeon/radeon_object.c index 1111111..2222222 100644 --- a/sys/dev/drm/radeon/radeon_object.c +++ b/sys/dev/drm/radeon/radeon_object.c @@ -611,12 +611,15 @@ int radeon_bo_get_surface_reg(struct radeon_bo *bo) lockdep_assert_held(&bo->tbo.resv->lock.base); if (!bo->tiling_flags) return 0; + /* The registry is device-global and steal touches OTHER BOs + * (reg->bo), which are not covered by this BO's reservation. + * Serialize against concurrent get/clear incl. the destroy path. */ + lockmgr(&rdev->surface_regs_lock, LK_EXCLUSIVE); + if (bo->surface_reg >= 0) { reg = &rdev->surface_regs[bo->surface_reg]; i = bo->surface_reg; goto out; } @@ -644,9 +647,11 @@ int radeon_bo_get_surface_reg(struct radeon_bo *bo) bo->surface_reg = i; reg->bo = bo; out: radeon_set_surface_reg(rdev, i, bo->tiling_flags, bo->pitch, bo->tbo.mem.start << PAGE_SHIFT, bo->tbo.num_pages << PAGE_SHIFT); + lockmgr(&rdev->surface_regs_lock, LK_RELEASE); return 0; } @@ -662,11 +667,14 @@ static void radeon_bo_clear_surface_reg(struct radeon_bo *bo) if (bo->surface_reg == -1) return; + /* Serialize against radeon_bo_get_surface_reg()'s steal scan, + * which dereferences reg->bo of this (possibly dying) BO. */ + lockmgr(&rdev->surface_regs_lock, LK_EXCLUSIVE); reg = &rdev->surface_regs[bo->surface_reg]; radeon_clear_surface_reg(rdev, bo->surface_reg); reg->bo = NULL; bo->surface_reg = -1; + lockmgr(&rdev->surface_regs_lock, LK_RELEASE); } int radeon_bo_set_tiling_flags(struct radeon_bo *bo,