Public > -----Original Message----- > From: Limonciello, Mario <[email protected]> > Sent: Monday, August 31, 2026 1:51 AM > To: Deucher, Alexander <[email protected]>; Joerg Roedel > <[email protected]> > Cc: [email protected]; Suthikulpanit, Suravee > <[email protected]>; Hegde, Vasant > <[email protected]>; Will Deacon <[email protected]>; Robin Murphy > <[email protected]>; open list:AMD IOMMU (AMD-VI) > <[email protected]>; Jatin Kataria <[email protected]>; Boqun Feng > <[email protected]>; Limonciello, Mario <[email protected]> > Subject: [PATCH 2/2] drm/amdgpu: Enable PerfOpt IOMMU perf optimization > when GPU in identity domain > > Enable PerfOpt via amd_iommu_enable_perfopt() when the GPU's > iommu_perfopt module parameter is enabled (default 1) and the GPU resides > in the identity domain. The identity domain means the GPU is already > performing direct DMA with the IOMMU only enforcing IR/IW permission bits > -- no GPA->SPA translations. > > amd_iommu_enable_perfopt() clears ATS, PRI, PASID and SVA for the device. > This is safe in identity domain because DTE[I]=0 means the IOMMU already > returns target abort for ATS requests from this peripheral and the GPU > manages its own TLB. > > PerfOpt is a soft, optional latency optimization: failing to arm it (for > example on > an IOMMU that does not implement the feature, which returns > -ENODEV) must not be fatal, so probe and resume warn and continue rather > than aborting. > > PERF_OPT_EN is a per-IOMMU control shared by all devices behind that > IOMMU; the IOMMU driver reference counts it so that on systems where > multiple devices share one IOMMU, one GPU's teardown does not clear the bit > while a peer still requires it. > > Arming PerfOpt trades IOMMU DMA containment for lower DMA latency. This > is enabled by default for GPUs in the identity domain as a deliberate, > documented policy and can be disabled with iommu_perfopt=0. > > The AMD IOMMU spec indicates this is only supported on integrated GPUs so > check explicitly for AMD_IS_APU (which is set by > amdgpu_device_ip_early_init()). > > PerfOpt is disabled during GPU init teardown and restored on resume. > > Signed-off-by: Mario Limonciello <[email protected]> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + > drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 41 > ++++++++++++++++++++++ > drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 12 +++++++ > 3 files changed, 54 insertions(+) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > index 7974f9b7944f3..930a78db7132e 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > @@ -156,6 +156,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 > index 44bed0ba64a37..75c74c72a52ea 100644 > --- 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> > @@ -3752,6 +3753,17 @@ > 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; } > + > /** > * amdgpu_device_init - initialize the driver > * > @@ -3958,6 +3970,18 @@ int amdgpu_device_init(struct amdgpu_device > *adev, > if (r) > return r; > > + if (amdgpu_iommu_perfopt != 0 && > + amdgpu_device_identity(adev) && > + adev->flags & AMD_IS_APU) { > + 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. > @@ -4327,6 +4351,9 @@ void amdgpu_device_fini_hw(struct > amdgpu_device *adev) > > amdgpu_gart_dummy_page_fini(adev); > > + if (amdgpu_iommu_perfopt != 0) > + amd_iommu_disable_perfopt(adev->pdev); > + > if (pci_dev_is_disconnected(adev->pdev)) > amdgpu_device_unmap_mmio(adev); > > @@ -4692,6 +4719,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_iommu_perfopt != 0 && amdgpu_device_identity(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 > index 5b08afde37baf..26ba7852e1ceb 100644 > --- 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 @@ -392,6 > +393,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 APU devices in identity domain). > + * 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 APU devices in identity domain, 0 = > +disable)"); module_param_named(iommu_perfopt, > amdgpu_iommu_perfopt, > +int, 0444);
For consistency with the other driver parameters, I would make the default -1 (auto) and have auto enable for APU devices. That way we can add 1 as an option later if we want to add a way to force it on in certain scenarios. Akex > + > /** > * DOC: runpm (int) > * Override for runtime power management control for dGPUs. The amdgpu > driver can dynamically power down > -- > 2.43.0
