[Why] sg_alloc_table_from_pages alloc too large continuous PFN pages under xen dom0. However, xen should check continuous MFN pages in range_straddles_page_boundary. When range_straddles_page_boundary return false, some cases fall back into swiotlb process and the continuous allocable page is not enough.
[How] In fact, xen swiotlb set max_segment default value as UINT_MAX and xen_swiotlb_init_early already change the value to PAGE_SIZE under xen dom0. However amdgpu driver doesn't use the value, which may cause issue such as swiotlb buffer full. Add amd_sg_segment_size according to iommu setting, the details are as follows: iommu setting | amd_sg_segment_size ------------------------------------------------------------------------------- iommu=on | UINT_MAX iommu=off && swiotlb on | IO_TLB_DEFAULT_SIZE(64M) xen_swiotlb on | PAGE_SIZE(4K) ------------------------------------------------------------------------------- Signed-off-by: Shane Xiao <shane.x...@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 134575a3893c..d081fcd22d6b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -80,6 +80,23 @@ static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev, false, size_in_page); } +static inline unsigned int amdgpu_sg_segment_size(void) +{ + unsigned int size = swiotlb_max_segment(); + + /* size=0 when amd iommu enabled */ + if (size == 0) + size = UINT_MAX; + + size = rounddown(size, PAGE_SIZE); + /* swiotlb_max_segment_size can return 1 byte when it means one page. */ + if (size < PAGE_SIZE) + size = PAGE_SIZE; + + return size; +} + + /** * amdgpu_evict_flags - Compute placement flags * @@ -760,9 +777,10 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_device *bdev, int r; /* Allocate an SG array and squash pages into it */ - r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0, - (u64)ttm->num_pages << PAGE_SHIFT, + r = sg_alloc_table_from_pages_segment(ttm->sg, ttm->pages, ttm->num_pages, 0, + (u64)ttm->num_pages << PAGE_SHIFT, amdgpu_sg_segment_size(), GFP_KERNEL); + if (r) goto release_sg; -- 2.25.1