drm/amdgpu: Add peer-to-peer support among PCIe connected AMD GPUs
[linux-2.6-block.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_device.c
index 620afd75dae763bdaf85b00baaf84d3586d4693d..b9d50cb6c236131b6f715b5c47b2e7c0cd5f3b59 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/pci.h>
 #include <linux/devcoredump.h>
 #include <generated/utsrelease.h>
+#include <linux/pci-p2pdma.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_probe_helper.h>
@@ -5499,6 +5500,36 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev)
        }
 }
 
+/**
+ * amdgpu_device_is_peer_accessible - Check peer access through PCIe BAR
+ *
+ * @adev: amdgpu_device pointer
+ * @peer_adev: amdgpu_device pointer for peer device trying to access @adev
+ *
+ * Return true if @peer_adev can access (DMA) @adev through the PCIe
+ * BAR, i.e. @adev is "large BAR" and the BAR matches the DMA mask of
+ * @peer_adev.
+ */
+bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev,
+                                     struct amdgpu_device *peer_adev)
+{
+#ifdef CONFIG_HSA_AMD_P2P
+       uint64_t address_mask = peer_adev->dev->dma_mask ?
+               ~*peer_adev->dev->dma_mask : ~((1ULL << 32) - 1);
+       resource_size_t aper_limit =
+               adev->gmc.aper_base + adev->gmc.aper_size - 1;
+       bool p2p_access = !(pci_p2pdma_distance_many(adev->pdev,
+                                       &peer_adev->dev, 1, true) < 0);
+
+       return pcie_p2p && p2p_access && (adev->gmc.visible_vram_size &&
+               adev->gmc.real_vram_size == adev->gmc.visible_vram_size &&
+               !(adev->gmc.aper_base & address_mask ||
+                 aper_limit & address_mask));
+#else
+       return false;
+#endif
+}
+
 int amdgpu_device_baco_enter(struct drm_device *dev)
 {
        struct amdgpu_device *adev = drm_to_adev(dev);