Allow early VRAM reads to fall back to a temporary BAR0 mapping
when the normal aperture mapping has not been established yet.

Signed-off-by: chong li <[email protected]>
Co-authored-by: Cursor <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 43 +++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 5442a1fc1c37..610d82b79de3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -743,6 +743,44 @@ void amdgpu_device_mm_access(struct amdgpu_device *adev, 
loff_t pos,
        drm_dev_exit(idx);
 }
 
+static int amdgpu_device_read_fb_via_bar0(struct amdgpu_device *adev,
+                                         u64 offset, void *buf, size_t size)
+{
+       resource_size_t bar_start, bar_size, map_base;
+       void __iomem *vram;
+       size_t map_offset, map_size;
+       unsigned long flags;
+       u64 end;
+
+       if (!buf || !size)
+               return -EINVAL;
+
+       flags = pci_resource_flags(adev->pdev, 0);
+       if ((flags & IORESOURCE_UNSET) || !(flags & IORESOURCE_MEM))
+               return -EINVAL;
+
+       bar_size = pci_resource_len(adev->pdev, 0);
+       if (!bar_size)
+               return -ENODEV;
+
+       if (check_add_overflow(offset, size, &end) || end > bar_size)
+               return -EINVAL;
+
+       bar_start = pci_resource_start(adev->pdev, 0);
+       map_offset = offset_in_page(offset);
+       map_base = bar_start + (offset & PAGE_MASK);
+       map_size = PAGE_ALIGN(map_offset + size);
+
+       vram = ioremap_wc(map_base, map_size);
+       if (!vram)
+               return -ENOMEM;
+
+       memcpy_fromio(buf, (u8 __iomem *)vram + map_offset, size);
+       iounmap(vram);
+
+       return 0;
+}
+
 /**
  * amdgpu_device_aper_access - access vram by vram aperture
  *
@@ -762,8 +800,11 @@ size_t amdgpu_device_aper_access(struct amdgpu_device 
*adev, loff_t pos,
        size_t count = 0;
        uint64_t last;
 
-       if (!adev->mman.aper_base_kaddr)
+       if (!adev->mman.aper_base_kaddr) {
+               if (!write && !amdgpu_device_read_fb_via_bar0(adev, pos, buf, 
size))
+                       return size;
                return 0;
+       }
 
        last = min(pos + size, adev->gmc.visible_vram_size);
        if (last > pos) {
-- 
2.48.1

Reply via email to