129 lines
4.3 KiB
Diff
129 lines
4.3 KiB
Diff
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
|
|
@@ -160,6 +160,7 @@ struct amdgpu_watchdog_timer {
|
|
* Modules parameters.
|
|
*/
|
|
extern int amdgpu_modeset;
|
|
+extern int amdgpu_iommu_perfopt;
|
|
extern unsigned int amdgpu_vram_limit;
|
|
extern int amdgpu_vis_vram_limit;
|
|
extern int amdgpu_gart_size;
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
|
|
@@ -33,6 +33,7 @@
|
|
#include <linux/console.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/iommu.h>
|
|
+#include <linux/amd-iommu.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/pci-p2pdma.h>
|
|
#include <linux/apple-gmux.h>
|
|
@@ -3842,6 +3843,28 @@ amdgpu_device_should_register_switcheroo(struct amdgpu_device *adev, bool px)
|
|
apple_gmux_detect(NULL, NULL)));
|
|
}
|
|
|
|
+static inline bool amdgpu_device_identity(struct amdgpu_device *adev)
|
|
+{
|
|
+ struct pci_dev *pdev = adev->pdev;
|
|
+ struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev);
|
|
+
|
|
+ if (!domain)
|
|
+ return false;
|
|
+
|
|
+ return domain->type == IOMMU_DOMAIN_IDENTITY;
|
|
+}
|
|
+
|
|
+static bool amdgpu_device_use_perfopt(struct amdgpu_device *adev)
|
|
+{
|
|
+ if (amdgpu_iommu_perfopt == 0)
|
|
+ return false;
|
|
+
|
|
+ if (!(adev->flags & AMD_IS_APU))
|
|
+ return false;
|
|
+
|
|
+ return amdgpu_device_identity(adev);
|
|
+}
|
|
+
|
|
/**
|
|
* amdgpu_device_init - initialize the driver
|
|
*
|
|
@@ -4048,6 +4071,16 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|
if (r)
|
|
return r;
|
|
|
|
+ if (amdgpu_device_use_perfopt(adev)) {
|
|
+ int perfopt_ret = amd_iommu_enable_perfopt(pdev);
|
|
+
|
|
+ /* Optional optimization; a failure to arm it must not abort probe. */
|
|
+ if (perfopt_ret)
|
|
+ dev_warn(adev->dev,
|
|
+ "Failed to enable IOMMU PerfOpt (%d); continuing without it\n",
|
|
+ perfopt_ret);
|
|
+ }
|
|
+
|
|
/*
|
|
* No need to remove conflicting FBs for non-display class devices.
|
|
* This prevents the sysfb from being freed accidently.
|
|
@@ -4416,6 +4449,9 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
|
|
|
|
amdgpu_gart_dummy_page_fini(adev);
|
|
|
|
+ if (amdgpu_device_use_perfopt(adev))
|
|
+ amd_iommu_disable_perfopt(adev->pdev);
|
|
+
|
|
if (pci_dev_is_disconnected(adev->pdev))
|
|
amdgpu_device_unmap_mmio(adev);
|
|
|
|
@@ -4779,6 +4815,20 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients)
|
|
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
|
return 0;
|
|
|
|
+ if (amdgpu_device_use_perfopt(adev)) {
|
|
+ int perfopt_ret = amd_iommu_enable_perfopt(adev->pdev);
|
|
+
|
|
+ /*
|
|
+ * Must not return on failure: a bare return would leak the
|
|
+ * SR-IOV VF exclusive-mode acquisition taken above (released
|
|
+ * via the exit: path).
|
|
+ */
|
|
+ if (perfopt_ret)
|
|
+ dev_warn(adev->dev,
|
|
+ "Failed to enable IOMMU PerfOpt (%d); continuing without it\n",
|
|
+ perfopt_ret);
|
|
+ }
|
|
+
|
|
if (adev->in_s0ix)
|
|
amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D0Entry);
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
|
|
@@ -185,6 +185,7 @@ char *amdgpu_disable_cu;
|
|
char *amdgpu_virtual_display;
|
|
int amdgpu_enforce_isolation = -1;
|
|
int amdgpu_modeset = -1;
|
|
+int amdgpu_iommu_perfopt = -1;
|
|
|
|
/* Specifies the default granularity for SVM, used in buffer
|
|
* migration and restoration of backing memory when handling
|
|
@@ -393,6 +394,17 @@ module_param_named(fw_load_type, amdgpu_fw_load_type, int, 0444);
|
|
MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)");
|
|
module_param_named(aspm, amdgpu_aspm, int, 0444);
|
|
|
|
+/**
|
|
+ * DOC: iommu_perfopt (int)
|
|
+ * Control the AMD IOMMU PerfOpt DMA-latency optimization
|
|
+ * (0 = disable; -1 = enable on supported devices).
|
|
+ * This arms the IOMMU PerfOpt control (IOMMU spec, MMIO Offset 016Ch, EFR PerfOptSup / PerfOptEn)
|
|
+ * Arming it disables ATS, PRI, PASID and SVA for the GPU and removes IOMMU DMA containment for it,
|
|
+ * trading isolation for lower DMA latency.
|
|
+ */
|
|
+MODULE_PARM_DESC(iommu_perfopt, "Control IOMMU PerfOpt DMA-latency optimization (-1 = enable on supported devices, 0 = disable)");
|
|
+module_param_named(iommu_perfopt, amdgpu_iommu_perfopt, int, 0444);
|
|
+
|
|
/**
|
|
* DOC: runpm (int)
|
|
* Override for runtime power management control for dGPUs. The amdgpu driver can dynamically power down
|