On ARM32 with CONFIG_ARM_DMA_USE_IOMMU, arch_setup_dma_ops() creates a
dma_iommu_mapping for every IOMMU-backed device and attaches its domain
to the device's IOMMU group. That domain is neither the group's default
nor its blocking domain, so when msm_iommu_new() later attaches the
domain the driver manages itself, __iommu_attach_group() refuses it:
if (group->domain && group->domain != group->default_domain &&
group->domain != group->blocking_domain)
return -EBUSY;
Both the GPU and the display controller are hit by this on apq8064
(IFC6410), leaving the board with no GPU and no display:
adreno
4300000.gpu: failed to load adreno gpu
adreno
4300000.gpu: probe with driver adreno failed with error -16
mdp4
5100000.display-controller: [drm:msm_drm_kms_init] *ERROR* failed to load kms
mdp4
5100000.display-controller: adev bind failed: -16
Other ARM32 DRM drivers that manage their own domains (tegra, rockchip,
exynos) drop the arch mapping first. Do the same in msm_iommu_new(),
which both the display and the GPU paths go through.
With this the GPU and the KMS device both initialise:
[drm] Initialized msm 1.13.0 for
4300000.gpu on minor 0
[drm] Initialized msm-kms 1.13.0 for
5100000.display-controller on minor 1
Assisted-by: Claude:claude-opus-5
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/743333/
Link: https://lore.kernel.org/r/20260730-fix-qcom-smmu-v2-3-18e0daf2d836@oss.qualcomm.com
#include <linux/adreno-smmu-priv.h>
#include <linux/io-pgtable.h>
#include <linux/kmemleak.h>
+
+#if defined(CONFIG_ARM_DMA_USE_IOMMU)
+#include <asm/dma-iommu.h>
+#else
+#define arm_iommu_detach_device(...) ({ })
+#define arm_iommu_release_mapping(...) ({ })
+#define to_dma_iommu_mapping(dev) NULL
+#endif
+
#include "msm_drv.h"
#include "msm_gpu_trace.h"
#include "msm_mmu.h"
mutex_init(&iommu->init_lock);
+ /*
+ * ARM32 attaches a DMA mapping domain to every IOMMU-backed device,
+ * which would make attaching our own domain fail with -EBUSY.
+ */
+ if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
+ struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+
+ if (mapping) {
+ arm_iommu_detach_device(dev);
+ arm_iommu_release_mapping(mapping);
+ }
+ }
+
ret = iommu_attach_device(iommu->domain, dev);
if (ret) {
iommu_domain_free(domain);