AMDGPU_BO_MAX_PLACEMENTS was 3 but amdgpu_bo_placement_from_domain() can emit up to four entries for CPU|GTT|VRAM|DOORBELL. Unprivileged GEM_CREATE with domains=0x47 writes past placements[] and triggers BUG_ON().
Increase the array to four and normalize mixed GDS/GWS/OA domain masks to CPU-only placement on all rebuild paths. Signed-off-by: Candice Li <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 18 ++++++++++++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 3 ++- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 6a0699746fbcd6..bcf81aba942842 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -431,8 +431,7 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, flags |= AMDGPU_GEM_CREATE_VRAM_CLEARED; /* create a gem object to contain this object in */ - if (args->in.domains & (AMDGPU_GEM_DOMAIN_GDS | - AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) { + if (args->in.domains & AMDGPU_GEM_DOMAIN_GDS_GWS_OA) { if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) { /* if gds bo is created from user space, it must be * passed to bo list diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h index b558336bc4c6ca..321db2ca29f4a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h @@ -31,6 +31,8 @@ */ #define AMDGPU_GEM_DOMAIN_MAX 0x3 +#define AMDGPU_GEM_DOMAIN_GDS_GWS_OA \ + (AMDGPU_GEM_DOMAIN_GDS | AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA) #define gem_to_amdgpu_bo(gobj) container_of((gobj), struct amdgpu_bo, tbo.base) extern const struct drm_gem_object_funcs amdgpu_gem_object_funcs; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index d4a9d5e8fb429a..bb02858cbebf0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -99,6 +99,19 @@ bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) return false; } +static u32 amdgpu_bo_filter_placement_domain(u32 domain) +{ + /* + * GDS/GWS/OA are not normal fallback placement domains. When mixed + * with CPU/GTT/VRAM/DOORBELL, fall back to CPU like amdgpu_bo_create(). + */ + if ((domain & AMDGPU_GEM_DOMAIN_GDS_GWS_OA) && + (domain & ~AMDGPU_GEM_DOMAIN_GDS_GWS_OA)) + return AMDGPU_GEM_DOMAIN_CPU; + + return domain; +} + /** * amdgpu_bo_placement_from_domain - set buffer's placement * @abo: &amdgpu_bo buffer object whose placement is to be set @@ -115,6 +128,8 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain) u64 flags = abo->flags; u32 c = 0; + domain = amdgpu_bo_filter_placement_domain(domain); + if (domain & AMDGPU_GEM_DOMAIN_VRAM) { unsigned int visible_pfn = adev->gmc.visible_vram_size >> PAGE_SHIFT; int8_t mem_id = KFD_XCP_MEM_ID(adev, abo->xcp_id); @@ -690,8 +705,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC; bo->tbo.bdev = &adev->mman.bdev; - if (bp->domain & (AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA | - AMDGPU_GEM_DOMAIN_GDS)) + if (bp->domain & AMDGPU_GEM_DOMAIN_GDS_GWS_OA) amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_CPU); else amdgpu_bo_placement_from_domain(bo, bp->domain); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index ff11a09034997e..20f4d8c243afdd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -37,7 +37,8 @@ #endif #define AMDGPU_BO_INVALID_OFFSET LONG_MAX -#define AMDGPU_BO_MAX_PLACEMENTS 3 +/* Covers CPU | GTT | VRAM | DOORBELL placement candidates */ +#define AMDGPU_BO_MAX_PLACEMENTS 4 /* BO flag to indicate a KFD userptr BO */ #define AMDGPU_AMDKFD_CREATE_USERPTR_BO (1ULL << 63) -- 2.25.1
