This is to work around a bug in function drm_prime_pages_to_sg if length
of nr_pages >= 4GB, by doing the same check for max_segment and then
calling sg_alloc_table_from_pages_segment directly instead.

This issue shows up on APU because VRAM is allocated as GTT memory. It
also fixes >=4GB GTT memory mapping for mGPUs with IOMMU isolation mode.

Signed-off-by: Philip Yang <philip.y...@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 50 ++++++++++++++-------
 1 file changed, 34 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
index 055ba2ea4c12..a203633fd629 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
@@ -171,18 +171,41 @@ static struct sg_table *amdgpu_dma_buf_map(struct 
dma_buf_attachment *attach,
        }
 
        switch (bo->tbo.resource->mem_type) {
-       case TTM_PL_TT:
-               sgt = drm_prime_pages_to_sg(obj->dev,
-                                           bo->tbo.ttm->pages,
-                                           bo->tbo.ttm->num_pages);
-               if (IS_ERR(sgt))
-                       return sgt;
-
-               if (dma_map_sgtable(attach->dev, sgt, dir,
-                                   DMA_ATTR_SKIP_CPU_SYNC))
-                       goto error_free;
-               break;
+       case TTM_PL_TT: {
+               size_t max_segment = 0;
+               u64 num_pages;
+               int err;
+
+               sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+               if (!sgt)
+                       return ERR_PTR(-ENOMEM);
+
+               if (obj->dev)
+                       max_segment = dma_max_mapping_size(obj->dev->dev);
+               if (max_segment == 0)
+                       max_segment = UINT_MAX;
+
+               /*
+                * Use u64, otherwise if length of num_pages >= 4GB then size
+                * (num_pages << PAGE_SHIFT) becomes 0
+                */
+               num_pages = bo->tbo.ttm->num_pages;
+               err = sg_alloc_table_from_pages_segment(sgt, bo->tbo.ttm->pages,
+                                                       num_pages, 0,
+                                                       num_pages << PAGE_SHIFT,
+                                                       max_segment, 
GFP_KERNEL);
+               if (err) {
+                       kfree(sgt);
+                       return ERR_PTR(err);
+               }
 
+               if (dma_map_sgtable(attach->dev, sgt, dir, 
DMA_ATTR_SKIP_CPU_SYNC)) {
+                       sg_free_table(sgt);
+                       kfree(sgt);
+                       return ERR_PTR(-EBUSY);
+               }
+               break;
+       }
        case TTM_PL_VRAM:
                r = amdgpu_vram_mgr_alloc_sgt(adev, bo->tbo.resource, 0,
                                              bo->tbo.base.size, attach->dev,
@@ -195,11 +218,6 @@ static struct sg_table *amdgpu_dma_buf_map(struct 
dma_buf_attachment *attach,
        }
 
        return sgt;
-
-error_free:
-       sg_free_table(sgt);
-       kfree(sgt);
-       return ERR_PTR(-EBUSY);
 }
 
 /**
-- 
2.35.1

Reply via email to